source: CLRX/CLRadeonExtender/trunk/amdbin/ROCmBinaries.cpp @ 3796

Last change on this file since 3796 was 3796, checked in by matszpk, 22 months ago

CLRadeonExtender: ElfBinGen?: Fixed counting region alignment (like in generate routine). Fixed including addrBase in elf header program entry.
ROCm: First working (not fully) version with got symbols. Fixed ROCm binaries for test (program entry).

File size: 87.6 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cassert>
22#include <cstdio>
23#include <cstring>
24#include <cstdint>
25#include <string>
26#include <vector>
27#include <algorithm>
28#include <utility>
29#include <unordered_set>
30#include <CLRX/amdbin/ElfBinaries.h>
31#include <CLRX/utils/Utilities.h>
32#include <CLRX/utils/MemAccess.h>
33#include <CLRX/utils/InputOutput.h>
34#include <CLRX/utils/Containers.h>
35#include <CLRX/amdbin/ROCmBinaries.h>
36
37using namespace CLRX;
38
39/*
40 * ROCm metadata YAML parser
41 */
42
43void ROCmKernelMetadata::initialize()
44{
45    langVersion[0] = langVersion[1] = BINGEN_NOTSUPPLIED;
46    reqdWorkGroupSize[0] = reqdWorkGroupSize[1] = reqdWorkGroupSize[2] = 0;
47    workGroupSizeHint[0] = workGroupSizeHint[1] = workGroupSizeHint[2] = 0;
48    kernargSegmentSize = BINGEN64_NOTSUPPLIED;
49    groupSegmentFixedSize = BINGEN64_NOTSUPPLIED;
50    privateSegmentFixedSize = BINGEN64_NOTSUPPLIED;
51    kernargSegmentAlign = BINGEN64_NOTSUPPLIED;
52    wavefrontSize = BINGEN_NOTSUPPLIED;
53    sgprsNum = BINGEN_NOTSUPPLIED;
54    vgprsNum = BINGEN_NOTSUPPLIED;
55    maxFlatWorkGroupSize = BINGEN64_NOTSUPPLIED;
56    fixedWorkGroupSize[0] = fixedWorkGroupSize[1] = fixedWorkGroupSize[2] = 0;
57    spilledSgprs = BINGEN_NOTSUPPLIED;
58    spilledVgprs = BINGEN_NOTSUPPLIED;
59}
60
61void ROCmMetadata::initialize()
62{
63    version[0] = 1;
64    version[1] = 0;
65}
66
67// return trailing spaces
68static size_t skipSpacesAndComments(const char*& ptr, const char* end, size_t& lineNo)
69{
70    const char* lineStart = ptr;
71    while (ptr != end)
72    {
73        lineStart = ptr;
74        while (ptr != end && *ptr!='\n' && isSpace(*ptr)) ptr++;
75        if (ptr == end)
76            break; // end of stream
77        if (*ptr=='#')
78        {
79            // skip comment
80            while (ptr != end && *ptr!='\n') ptr++;
81            if (ptr == end)
82                return 0; // no trailing spaces and end
83        }
84        else if (*ptr!='\n')
85            break; // no comment and no end of line
86        else
87        {
88            ptr++;
89            lineNo++; // next line
90        }
91    }
92    return ptr - lineStart;
93}
94
95static inline void skipSpacesToLineEnd(const char*& ptr, const char* end)
96{
97    while (ptr != end && *ptr!='\n' && isSpace(*ptr)) ptr++;
98}
99
100static void skipSpacesToNextLine(const char*& ptr, const char* end, size_t& lineNo)
101{
102    skipSpacesToLineEnd(ptr, end);
103    if (ptr != end && *ptr != '\n' && *ptr!='#')
104        throw ParseException(lineNo, "Garbages at line");
105    if (ptr != end && *ptr == '#')
106        // skip comment at end of line
107        while (ptr!=end && *ptr!='\n') ptr++;
108    if (ptr!=end)
109    {   // newline
110        ptr++;
111        lineNo++;
112    }
113}
114
115enum class YAMLValType
116{
117    NONE,
118    NIL,
119    BOOL,
120    INT,
121    FLOAT,
122    STRING,
123    SEQ
124};
125
126static YAMLValType parseYAMLType(const char*& ptr, const char* end, size_t lineNo)
127{
128    if (ptr+2>end || *ptr!='!' || ptr[1]!='!')
129        return YAMLValType::NONE; // no type
130    if (ptr+7 && ::strncmp(ptr+2, "null", 4)==0 && isSpace(ptr[6]) && ptr[6]!='\n')
131    {
132        ptr += 6;
133        return YAMLValType::NIL;
134    }
135    else if (ptr+7 && ::strncmp(ptr+2, "bool", 4)==0 && isSpace(ptr[6]) && ptr[6]!='\n')
136    {
137        ptr += 6;
138        return YAMLValType::BOOL;
139    }
140    else if (ptr+6 && ::strncmp(ptr+2, "int", 3)==0 && isSpace(ptr[5]) && ptr[5]!='\n')
141    {
142        ptr += 5;
143        return YAMLValType::INT;
144    }
145    else if (ptr+8 && ::strncmp(ptr+2, "float", 5)==0 && isSpace(ptr[7]) && ptr[7]!='\n')
146    {
147        ptr += 7;
148        return YAMLValType::FLOAT;
149    }
150    else if (ptr+6 && ::strncmp(ptr+2, "str", 3)==0 && isSpace(ptr[5]) && ptr[5]!='\n')
151    {
152        ptr += 5;
153        return YAMLValType::STRING;
154    }
155    else if (ptr+6 && ::strncmp(ptr+2, "seq", 3)==0 && isSpace(ptr[5]) && ptr[5]!='\n')
156    {
157        ptr += 5;
158        return YAMLValType::SEQ;
159    }
160    throw ParseException(lineNo, "Unknown YAML value type");
161}
162
163// parse YAML key (keywords - recognized keys)
164static size_t parseYAMLKey(const char*& ptr, const char* end, size_t lineNo,
165            size_t keywordsNum, const char** keywords)
166{
167    const char* keyPtr = ptr;
168    while (ptr != end && (isAlnum(*ptr) || *ptr=='_')) ptr++;
169    if (keyPtr == end)
170        throw ParseException(lineNo, "Expected key name");
171    const char* keyEnd = ptr;
172    skipSpacesToLineEnd(ptr, end);
173    if (ptr == end || *ptr!=':')
174        throw ParseException(lineNo, "Expected colon");
175    ptr++;
176    const char* afterColon = ptr;
177    skipSpacesToLineEnd(ptr, end);
178    if (afterColon == ptr && ptr != end && *ptr!='\n')
179        // only if not immediate newline
180        throw ParseException(lineNo, "After key and colon must be space");
181    CString keyword(keyPtr, keyEnd);
182    const size_t index = binaryFind(keywords, keywords+keywordsNum,
183                        keyword.c_str(), CStringLess()) - keywords;
184    return index;
185}
186
187// parse YAML integer value
188template<typename T>
189static T parseYAMLIntValue(const char*& ptr, const char* end, size_t& lineNo,
190                bool singleValue = false)
191{
192    skipSpacesToLineEnd(ptr, end);
193    if (ptr == end || *ptr=='\n')
194        throw ParseException(lineNo, "Expected integer value");
195   
196    // skip !!int
197    YAMLValType valType = parseYAMLType(ptr, end, lineNo);
198    if (valType == YAMLValType::INT)
199    {   // if
200        skipSpacesToLineEnd(ptr, end);
201        if (ptr == end || *ptr=='\n')
202            throw ParseException(lineNo, "Expected integer value");
203    }
204    else if (valType != YAMLValType::NONE)
205        throw ParseException(lineNo, "Expected value of integer type");
206   
207    T value = 0;
208    try
209    { value = cstrtovCStyle<T>(ptr, end, ptr); }
210    catch(const ParseException& ex)
211    { throw ParseException(lineNo, ex.what()); }
212   
213    if (singleValue)
214        skipSpacesToNextLine(ptr, end, lineNo);
215    return value;
216}
217
218// parse YAML boolean value
219static bool parseYAMLBoolValue(const char*& ptr, const char* end, size_t& lineNo,
220        bool singleValue = false)
221{
222    skipSpacesToLineEnd(ptr, end);
223    if (ptr == end || *ptr=='\n')
224        throw ParseException(lineNo, "Expected boolean value");
225   
226    // skip !!bool
227    YAMLValType valType = parseYAMLType(ptr, end, lineNo);
228    if (valType == YAMLValType::BOOL)
229    {   // if
230        skipSpacesToLineEnd(ptr, end);
231        if (ptr == end || *ptr=='\n')
232            throw ParseException(lineNo, "Expected boolean value");
233    }
234    else if (valType != YAMLValType::NONE)
235        throw ParseException(lineNo, "Expected value of boolean type");
236   
237    const char* wordPtr = ptr;
238    while(ptr != end && isAlnum(*ptr)) ptr++;
239    CString word(wordPtr, ptr);
240   
241    bool value = false;
242    bool isSet = false;
243    for (const char* v: { "1", "true", "t", "on", "yes", "y"})
244        if (::strcasecmp(word.c_str(), v) == 0)
245        {
246            isSet = true;
247            value = true;
248            break;
249        }
250    if (!isSet)
251        for (const char* v: { "0", "false", "f", "off", "no", "n"})
252            if (::strcasecmp(word.c_str(), v) == 0)
253            {
254                isSet = true;
255                value = false;
256                break;
257            }
258    if (!isSet)
259        throw ParseException(lineNo, "This is not boolean value");
260   
261    if (singleValue)
262        skipSpacesToNextLine(ptr, end, lineNo);
263    return value;
264}
265
266// trim spaces (remove spaces from start and end)
267static std::string trimStrSpaces(const std::string& str)
268{
269    size_t i = 0;
270    const size_t sz = str.size();
271    while (i!=sz && isSpace(str[i])) i++;
272    if (i == sz) return "";
273    size_t j = sz-1;
274    while (j>i && isSpace(str[j])) j--;
275    return str.substr(i, j-i+1);
276}
277
278static std::string parseYAMLString(const char*& linePtr, const char* end,
279            size_t& lineNo)
280{
281    std::string strarray;
282    if (linePtr == end || (*linePtr != '"' && *linePtr != '\''))
283    {
284        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
285        throw ParseException(lineNo, "Expected string");
286    }
287    const char termChar = *linePtr;
288    linePtr++;
289   
290    // main loop, where is character parsing
291    while (linePtr != end && *linePtr != termChar)
292    {
293        if (*linePtr == '\\')
294        {
295            // escape
296            linePtr++;
297            uint16_t value;
298            if (linePtr == end)
299                throw ParseException(lineNo, "Unterminated character of string");
300            if (*linePtr == 'x')
301            {
302                // hex literal
303                linePtr++;
304                if (linePtr == end)
305                    throw ParseException(lineNo, "Unterminated character of string");
306                value = 0;
307                if (isXDigit(*linePtr))
308                    for (; linePtr != end; linePtr++)
309                    {
310                        cxuint digit;
311                        if (*linePtr >= '0' && *linePtr <= '9')
312                            digit = *linePtr-'0';
313                        else if (*linePtr >= 'a' && *linePtr <= 'f')
314                            digit = *linePtr-'a'+10;
315                        else if (*linePtr >= 'A' && *linePtr <= 'F')
316                            digit = *linePtr-'A'+10;
317                        else
318                            break;
319                        value = (value<<4) + digit;
320                    }
321                else
322                    throw ParseException(lineNo, "Expected hexadecimal character code");
323                value &= 0xff;
324            }
325            else if (isODigit(*linePtr))
326            {
327                // octal literal
328                value = 0;
329                for (cxuint i = 0; linePtr != end && i < 3; i++, linePtr++)
330                {
331                    if (!isODigit(*linePtr))
332                        break;
333                    value = (value<<3) + uint64_t(*linePtr-'0');
334                    // checking range
335                    if (value > 255)
336                        throw ParseException(lineNo, "Octal code out of range");
337                }
338            }
339            else
340            {
341                // normal escapes
342                const char c = *linePtr++;
343                switch (c)
344                {
345                    case 'a':
346                        value = '\a';
347                        break;
348                    case 'b':
349                        value = '\b';
350                        break;
351                    case 'r':
352                        value = '\r';
353                        break;
354                    case 'n':
355                        value = '\n';
356                        break;
357                    case 'f':
358                        value = '\f';
359                        break;
360                    case 'v':
361                        value = '\v';
362                        break;
363                    case 't':
364                        value = '\t';
365                        break;
366                    case '\\':
367                        value = '\\';
368                        break;
369                    case '\'':
370                        value = '\'';
371                        break;
372                    case '\"':
373                        value = '\"';
374                        break;
375                    default:
376                        value = c;
377                }
378            }
379            strarray.push_back(value);
380        }
381        else // regular character
382        {
383            if (*linePtr=='\n')
384                lineNo++;
385            strarray.push_back(*linePtr++);
386        }
387    }
388    if (linePtr == end)
389        throw ParseException(lineNo, "Unterminated string");
390    linePtr++;
391    return strarray;
392}
393
394static std::string parseYAMLStringValue(const char*& ptr, const char* end, size_t& lineNo,
395                    cxuint prevIndent, bool singleValue = false, bool blockAccept = true)
396{
397    skipSpacesToLineEnd(ptr, end);
398    if (ptr == end)
399        return "";
400   
401    // skip !!str
402    YAMLValType valType = parseYAMLType(ptr, end, lineNo);
403    if (valType == YAMLValType::STRING)
404    {   // if
405        skipSpacesToLineEnd(ptr, end);
406        if (ptr == end)
407            return "";
408    }
409    else if (valType != YAMLValType::NONE)
410        throw ParseException(lineNo, "Expected value of string type");
411   
412    std::string buf;
413    if (*ptr=='"' || *ptr== '\'')
414        buf = parseYAMLString(ptr, end, lineNo);
415    // otherwise parse stream
416    else if (*ptr == '|' || *ptr == '>')
417    {
418        if (!blockAccept)
419            throw ParseException(lineNo, "Illegal block string start");
420        // multiline
421        bool newLineFold = *ptr=='>';
422        ptr++;
423        skipSpacesToLineEnd(ptr, end);
424        if (ptr!=end && *ptr!='\n')
425            throw ParseException(lineNo, "Garbages at string block");
426        if (ptr == end)
427            return ""; // end
428        lineNo++;
429        ptr++; // skip newline
430        const char* lineStart = ptr;
431        skipSpacesToLineEnd(ptr, end);
432        size_t indent = ptr - lineStart;
433        if (indent <= prevIndent)
434            throw ParseException(lineNo, "Unindented string block");
435       
436        std::string buf;
437        while(ptr != end)
438        {
439            const char* strStart = ptr;
440            while (ptr != end && *ptr!='\n') ptr++;
441            buf.append(strStart, ptr);
442           
443            if (ptr != end) // if new line
444            {
445                lineNo++;
446                ptr++;
447            }
448            else // end of stream
449                break;
450           
451            const char* lineStart = ptr;
452            skipSpacesToLineEnd(ptr, end);
453            bool emptyLines = false;
454            while (size_t(ptr - lineStart) <= indent)
455            {
456                if (ptr != end && *ptr=='\n')
457                {
458                    // empty line
459                    buf.append("\n");
460                    ptr++;
461                    lineNo++;
462                    lineStart = ptr;
463                    skipSpacesToLineEnd(ptr, end);
464                    emptyLines = true;
465                    continue;
466                }
467                // if smaller indent
468                if (size_t(ptr - lineStart) < indent)
469                {
470                    buf.append("\n"); // always add newline at last line
471                    if (ptr != end)
472                        ptr = lineStart;
473                    return buf;
474                }
475                else // if this same and not end of line
476                    break;
477            }
478           
479            if (!emptyLines || !newLineFold)
480                // add missing newline after line with text
481                // only if no emptyLines or no newLineFold
482                buf.append(newLineFold ? " " : "\n");
483            // to indent
484            ptr = lineStart + indent;
485        }
486        return buf;
487    }
488    else
489    {
490        // single line string (unquoted)
491        const char* strStart = ptr;
492        // automatically trim spaces at ends
493        const char* strEnd = ptr;
494        while (ptr != end && *ptr!='\n' && *ptr!='#')
495        {
496            if (!isSpace(*ptr))
497                strEnd = ptr; // to trim at end
498            ptr++;
499        }
500        if (strEnd != end && !isSpace(*strEnd))
501            strEnd++;
502       
503        buf.assign(strStart, strEnd);
504    }
505   
506    if (singleValue)
507        skipSpacesToNextLine(ptr, end, lineNo);
508    return buf;
509}
510
511/// element consumer class
512class CLRX_INTERNAL YAMLElemConsumer
513{
514public:
515    virtual void consume(const char*& ptr, const char* end, size_t& lineNo,
516                cxuint prevIndent, bool singleValue, bool blockAccept) = 0;
517};
518
519static void parseYAMLValArray(const char*& ptr, const char* end, size_t& lineNo,
520            size_t prevIndent, YAMLElemConsumer* elemConsumer, bool singleValue = false)
521{
522    skipSpacesToLineEnd(ptr, end);
523    if (ptr == end)
524        return;
525   
526    // skip !!int
527    YAMLValType valType = parseYAMLType(ptr, end, lineNo);
528    if (valType == YAMLValType::SEQ)
529    {   // if
530        skipSpacesToLineEnd(ptr, end);
531        if (ptr == end)
532            return;
533    }
534    else if (valType != YAMLValType::NONE)
535        throw ParseException(lineNo, "Expected value of sequence type");
536   
537    if (*ptr == '[')
538    {
539        // parse array []
540        ptr++;
541        skipSpacesAndComments(ptr, end, lineNo);
542        while (ptr != end)
543        {
544            // parse in line
545            elemConsumer->consume(ptr, end, lineNo, 0, false, false);
546            skipSpacesAndComments(ptr, end, lineNo);
547            if (ptr!=end && *ptr==']')
548                // just end
549                break;
550            else if (ptr==end || *ptr!=',')
551                throw ParseException(lineNo, "Expected ','");
552            ptr++;
553            skipSpacesAndComments(ptr, end, lineNo);
554        }
555        if (ptr == end)
556            throw ParseException(lineNo, "Unterminated array");
557        ptr++;
558       
559        if (singleValue)
560            skipSpacesToNextLine(ptr, end, lineNo);
561        return;
562    }
563    // parse sequence
564    size_t oldLineNo = lineNo;
565    size_t indent0 = skipSpacesAndComments(ptr, end, lineNo);
566    if (ptr == end || lineNo == oldLineNo)
567        throw ParseException(lineNo, "Expected sequence of values");
568   
569    if (indent0 < prevIndent)
570        throw ParseException(lineNo, "Unindented sequence of objects");
571   
572    // main loop to parse sequence
573    while (ptr != end)
574    {
575        if (*ptr != '-')
576            throw ParseException(lineNo, "No '-' before element value");
577        ptr++;
578        const char* afterMinus = ptr;
579        skipSpacesToLineEnd(ptr, end);
580        if (afterMinus == ptr)
581            throw ParseException(lineNo, "No spaces after '-'");
582        elemConsumer->consume(ptr, end, lineNo, indent0, true, true);
583       
584        size_t indent = skipSpacesAndComments(ptr, end, lineNo);
585        if (indent < indent0)
586        {
587            // if parent level
588            ptr -= indent;
589            break;
590        }
591        if (indent != indent0)
592            throw ParseException(lineNo, "Wrong indentation of element");
593    }
594}
595
596// integer element consumer
597template<typename T>
598class CLRX_INTERNAL YAMLIntArrayConsumer: public YAMLElemConsumer
599{
600private:
601    size_t elemsNum;
602    size_t requiredElemsNum;
603public:
604    T* array;
605   
606    YAMLIntArrayConsumer(size_t reqElemsNum, T* _array)
607            : elemsNum(0), requiredElemsNum(reqElemsNum), array(_array)
608    { }
609   
610    virtual void consume(const char*& ptr, const char* end, size_t& lineNo,
611                cxuint prevIndent, bool singleValue, bool blockAccept)
612    {
613        if (elemsNum == requiredElemsNum)
614            throw ParseException(lineNo, "Too many elements");
615        try
616        { array[elemsNum] = cstrtovCStyle<T>(ptr, end, ptr); }
617        catch(const ParseException& ex)
618        { throw ParseException(lineNo, ex.what()); }
619        elemsNum++;
620        if (singleValue)
621            skipSpacesToNextLine(ptr, end, lineNo);
622    }
623};
624
625// printf info string consumer
626class CLRX_INTERNAL YAMLPrintfVectorConsumer: public YAMLElemConsumer
627{
628private:
629    std::unordered_set<cxuint> printfIds;
630public:
631    std::vector<ROCmPrintfInfo>& printfInfos;
632   
633    YAMLPrintfVectorConsumer(std::vector<ROCmPrintfInfo>& _printInfos)
634        : printfInfos(_printInfos)
635    { }
636   
637    virtual void consume(const char*& ptr, const char* end, size_t& lineNo,
638                cxuint prevIndent, bool singleValue, bool blockAccept)
639    {
640        const size_t oldLineNo = lineNo;
641        std::string str = parseYAMLStringValue(ptr, end, lineNo, prevIndent,
642                                singleValue, blockAccept);
643        // parse printf string
644        ROCmPrintfInfo printfInfo{};
645       
646        const char* ptr2 = str.c_str();
647        const char* end2 = str.c_str() + str.size();
648        skipSpacesToLineEnd(ptr2, end2);
649        try
650        { printfInfo.id = cstrtovCStyle<uint32_t>(ptr2, end2, ptr2); }
651        catch(const ParseException& ex)
652        { throw ParseException(oldLineNo, ex.what()); }
653       
654        // check printf id uniqueness
655        if (!printfIds.insert(printfInfo.id).second)
656            throw ParseException(oldLineNo, "Duplicate of printf id");
657       
658        skipSpacesToLineEnd(ptr2, end2);
659        if (ptr2==end || *ptr2!=':')
660            throw ParseException(oldLineNo, "No colon after printf callId");
661        ptr2++;
662        skipSpacesToLineEnd(ptr2, end2);
663        uint32_t argsNum = cstrtovCStyle<uint32_t>(ptr2, end2, ptr2);
664        skipSpacesToLineEnd(ptr2, end2);
665        if (ptr2==end || *ptr2!=':')
666            throw ParseException(oldLineNo, "No colon after printf argsNum");
667        ptr2++;
668       
669        printfInfo.argSizes.resize(argsNum);
670       
671        // parse arg sizes
672        for (size_t i = 0; i < argsNum; i++)
673        {
674            skipSpacesToLineEnd(ptr2, end2);
675            printfInfo.argSizes[i] = cstrtovCStyle<uint32_t>(ptr2, end2, ptr2);
676            skipSpacesToLineEnd(ptr2, end2);
677            if (ptr2==end || *ptr2!=':')
678                throw ParseException(lineNo, "No colon after printf argsNum");
679            ptr2++;
680        }
681        // format
682        printfInfo.format.assign(ptr2, end2);
683       
684        printfInfos.push_back(printfInfo);
685    }
686};
687
688// skip YAML value after key
689static void skipYAMLValue(const char*& ptr, const char* end, size_t& lineNo,
690                cxuint prevIndent, bool singleValue = true)
691{
692    skipSpacesToLineEnd(ptr, end);
693    if (ptr+2 >= end && ptr[0]=='!' && ptr[1]=='!')
694    {   // skip !!xxxxx
695        ptr+=2;
696        while (ptr!=end && isAlpha(*ptr)) ptr++;
697        skipSpacesToLineEnd(ptr, end);
698    }
699   
700    if (ptr==end || (*ptr!='\'' && *ptr!='"' && *ptr!='|' && *ptr!='>' && *ptr !='[' &&
701                *ptr!='#' && *ptr!='\n'))
702    {
703        while (ptr!=end && *ptr!='\n') ptr++;
704        skipSpacesToNextLine(ptr, end, lineNo);
705        return;
706    }
707    // string
708    if (*ptr=='\'' || *ptr=='"')
709    {
710        const char delim = *ptr++;
711        bool escape = false;
712        while(ptr!=end && (escape || *ptr!=delim))
713        {
714            if (!escape && *ptr=='\\')
715                escape = true;
716            else if (escape)
717                escape = false;
718            if (*ptr=='\n') lineNo++;
719            ptr++;
720        }
721        if (ptr==end)
722            throw ParseException(lineNo, "Unterminated string");
723        ptr++;
724        if (singleValue)
725            skipSpacesToNextLine(ptr, end, lineNo);
726    }
727    else if (*ptr=='[')
728    {   // otherwise [array]
729        ptr++;
730        skipSpacesAndComments(ptr, end, lineNo);
731        while (ptr != end)
732        {
733            // parse in line
734            if (ptr!=end && (*ptr=='\'' || *ptr=='"'))
735                // skip YAML string
736                skipYAMLValue(ptr, end, lineNo, 0, false);
737            else
738                while (ptr!=end && *ptr!='\n' &&
739                            *ptr!='#' && *ptr!=',' && *ptr!=']') ptr++;
740            skipSpacesAndComments(ptr, end, lineNo);
741           
742            if (ptr!=end && *ptr==']')
743                // just end
744                break;
745            else if (ptr!=end && *ptr!=',')
746                throw ParseException(lineNo, "Expected ','");
747            ptr++;
748            skipSpacesAndComments(ptr, end, lineNo);
749        }
750        if (ptr == end)
751            throw ParseException(lineNo, "Unterminated array");
752        ptr++;
753        skipSpacesToNextLine(ptr, end, lineNo);
754    }
755    else
756    {   // block value
757        bool blockValue = false;
758        if (ptr!=end && (*ptr=='|' || *ptr=='>'))
759        {
760            ptr++; // skip '|' or '>'
761            blockValue = true;
762        }
763        if (ptr!=end && *ptr=='#')
764            while (ptr!=end && *ptr!='\n') ptr++;
765        else
766            skipSpacesToLineEnd(ptr, end);
767        if (ptr!=end && *ptr!='\n')
768            throw ParseException(lineNo, "Garbages before block or children");
769        ptr++;
770        lineNo++;
771        // skip all lines indented beyound previous level
772        while (ptr != end)
773        {
774            const char* lineStart = ptr;
775            skipSpacesToLineEnd(ptr, end);
776            if (ptr == end)
777            {
778                ptr++;
779                lineNo++;
780                continue;
781            }
782            if (size_t(ptr-lineStart) <= prevIndent && *ptr!='\n' &&
783                (blockValue || *ptr!='#'))
784                // if indent is short and not empty line (same spaces) or
785                // or with only comment and not blockValue
786            {
787                ptr = lineStart;
788                break;
789            }
790           
791            while (ptr!=end && *ptr!='\n') ptr++;
792            if (ptr!=end)
793            {
794                lineNo++;
795                ptr++;
796            }
797        }
798    }
799}
800
801enum {
802    ROCMMT_MAIN_KERNELS = 0, ROCMMT_MAIN_PRINTF,  ROCMMT_MAIN_VERSION
803};
804
805static const char* mainMetadataKeywords[] =
806{
807    "Kernels", "Printf", "Version"
808};
809
810static const size_t mainMetadataKeywordsNum =
811        sizeof(mainMetadataKeywords) / sizeof(const char*);
812
813enum {
814    ROCMMT_KERNEL_ARGS = 0, ROCMMT_KERNEL_ATTRS, ROCMMT_KERNEL_CODEPROPS,
815    ROCMMT_KERNEL_LANGUAGE, ROCMMT_KERNEL_LANGUAGE_VERSION,
816    ROCMMT_KERNEL_NAME, ROCMMT_KERNEL_SYMBOLNAME
817};
818
819static const char* kernelMetadataKeywords[] =
820{
821    "Args", "Attrs", "CodeProps", "Language", "LanguageVersion", "Name", "SymbolName"
822};
823
824static const size_t kernelMetadataKeywordsNum =
825        sizeof(kernelMetadataKeywords) / sizeof(const char*);
826
827enum {
828    ROCMMT_ATTRS_REQD_WORK_GROUP_SIZE = 0, ROCMMT_ATTRS_RUNTIME_HANDLE,
829    ROCMMT_ATTRS_VECTYPEHINT, ROCMMT_ATTRS_WORK_GROUP_SIZE_HINT
830};
831
832static const char* kernelAttrMetadataKeywords[] =
833{
834    "ReqdWorkGroupSize", "RuntimeHandle", "VecTypeHint", "WorkGroupSizeHint"
835};
836
837static const size_t kernelAttrMetadataKeywordsNum =
838        sizeof(kernelAttrMetadataKeywords) / sizeof(const char*);
839
840enum {
841    ROCMMT_CODEPROPS_FIXED_WORK_GROUP_SIZE = 0, ROCMMT_CODEPROPS_GROUP_SEGMENT_FIXED_SIZE,
842    ROCMMT_CODEPROPS_KERNARG_SEGMENT_ALIGN, ROCMMT_CODEPROPS_KERNARG_SEGMENT_SIZE,
843    ROCMMT_CODEPROPS_MAX_FLAT_WORK_GROUP_SIZE, ROCMMT_CODEPROPS_NUM_SGPRS,
844    ROCMMT_CODEPROPS_NUM_SPILLED_SGPRS, ROCMMT_CODEPROPS_NUM_SPILLED_VGPRS,
845    ROCMMT_CODEPROPS_NUM_VGPRS, ROCMMT_CODEPROPS_PRIVATE_SEGMENT_FIXED_SIZE,
846    ROCMMT_CODEPROPS_WAVEFRONT_SIZE
847};
848
849static const char* kernelCodePropsKeywords[] =
850{
851    "FixedWorkGroupSize", "GroupSegmentFixedSize", "KernargSegmentAlign",
852    "KernargSegmentSize", "MaxFlatWorkGroupSize", "NumSGPRs",
853    "NumSpilledSGPRs", "NumSpilledVGPRs", "NumVGPRs", "PrivateSegmentFixedSize",
854    "WavefrontSize"
855};
856
857static const size_t kernelCodePropsKeywordsNum =
858        sizeof(kernelCodePropsKeywords) / sizeof(const char*);
859
860enum {
861    ROCMMT_ARGS_ACCQUAL = 0, ROCMMT_ARGS_ACTUALACCQUAL, ROCMMT_ARGS_ADDRSPACEQUAL,
862    ROCMMT_ARGS_ALIGN, ROCMMT_ARGS_ISCONST, ROCMMT_ARGS_ISPIPE, ROCMMT_ARGS_ISRESTRICT,
863    ROCMMT_ARGS_ISVOLATILE, ROCMMT_ARGS_NAME, ROCMMT_ARGS_POINTEE_ALIGN,
864    ROCMMT_ARGS_SIZE, ROCMMT_ARGS_TYPENAME, ROCMMT_ARGS_VALUEKIND,
865    ROCMMT_ARGS_VALUETYPE
866};
867
868static const char* kernelArgInfosKeywords[] =
869{
870    "AccQual", "ActualAccQual", "AddrSpaceQual", "Align", "IsConst", "IsPipe",
871    "IsRestrict", "IsVolatile", "Name", "PointeeAlign", "Size", "TypeName",
872    "ValueKind", "ValueType"
873};
874
875static const size_t kernelArgInfosKeywordsNum =
876        sizeof(kernelArgInfosKeywords) / sizeof(const char*);
877
878static const std::pair<const char*, ROCmValueKind> rocmValueKindNamesMap[] =
879{
880    { "ByValue", ROCmValueKind::BY_VALUE },
881    { "DynamicSharedPointer", ROCmValueKind::DYN_SHARED_PTR },
882    { "GlobalBuffer", ROCmValueKind::GLOBAL_BUFFER },
883    { "HiddenCompletionAction", ROCmValueKind::HIDDEN_COMPLETION_ACTION },
884    { "HiddenDefaultQueue", ROCmValueKind::HIDDEN_DEFAULT_QUEUE },
885    { "HiddenGlobalOffsetX", ROCmValueKind::HIDDEN_GLOBAL_OFFSET_X },
886    { "HiddenGlobalOffsetY", ROCmValueKind::HIDDEN_GLOBAL_OFFSET_Y },
887    { "HiddenGlobalOffsetZ", ROCmValueKind::HIDDEN_GLOBAL_OFFSET_Z },
888    { "HiddenNone", ROCmValueKind::HIDDEN_NONE },
889    { "HiddenPrintfBuffer", ROCmValueKind::HIDDEN_PRINTF_BUFFER },
890    { "Image", ROCmValueKind::IMAGE },
891    { "Pipe", ROCmValueKind::PIPE },
892    { "Queue", ROCmValueKind::QUEUE },
893    { "Sampler", ROCmValueKind::SAMPLER }
894};
895
896static const size_t rocmValueKindNamesNum =
897        sizeof(rocmValueKindNamesMap) / sizeof(std::pair<const char*, ROCmValueKind>);
898
899static const std::pair<const char*, ROCmValueType> rocmValueTypeNamesMap[] =
900{
901    { "F16", ROCmValueType::FLOAT16 },
902    { "F32", ROCmValueType::FLOAT32 },
903    { "F64", ROCmValueType::FLOAT64 },
904    { "I16", ROCmValueType::INT16 },
905    { "I32", ROCmValueType::INT32 },
906    { "I64", ROCmValueType::INT64 },
907    { "I8", ROCmValueType::INT8 },
908    { "Struct", ROCmValueType::STRUCTURE },
909    { "U16", ROCmValueType::UINT16 },
910    { "U32", ROCmValueType::UINT32 },
911    { "U64", ROCmValueType::UINT64 },
912    { "U8", ROCmValueType::UINT8 }
913};
914
915static const size_t rocmValueTypeNamesNum =
916        sizeof(rocmValueTypeNamesMap) / sizeof(std::pair<const char*, ROCmValueType>);
917
918static const char* rocmAddrSpaceTypesTbl[] =
919{ "Private", "Global", "Constant", "Local", "Generic", "Region" };
920
921static const char* rocmAccessQualifierTbl[] =
922{ "Default", "ReadOnly", "WriteOnly", "ReadWrite" };
923
924static void parseROCmMetadata(size_t metadataSize, const char* metadata,
925                ROCmMetadata& metadataInfo)
926{
927    const char* ptr = metadata;
928    const char* end = metadata + metadataSize;
929    size_t lineNo = 1;
930    // init metadata info object
931    metadataInfo.kernels.clear();
932    metadataInfo.printfInfos.clear();
933    metadataInfo.version[0] = metadataInfo.version[1] = 0;
934   
935    std::vector<ROCmKernelMetadata>& kernels = metadataInfo.kernels;
936   
937    cxuint levels[6] = { UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX };
938    cxuint curLevel = 0;
939    bool inKernels = false;
940    bool inKernel = false;
941    bool inKernelArgs = false;
942    bool inKernelArg = false;
943    bool inKernelCodeProps = false;
944    bool inKernelAttrs = false;
945    bool canToNextLevel = false;
946   
947    size_t oldLineNo = 0;
948    while (ptr != end)
949    {
950        cxuint level = skipSpacesAndComments(ptr, end, lineNo);
951        if (ptr == end || lineNo == oldLineNo)
952            throw ParseException(lineNo, "Expected new line");
953       
954        if (levels[curLevel] == UINT_MAX)
955            levels[curLevel] = level;
956        else if (levels[curLevel] < level)
957        {
958            if (canToNextLevel)
959                // go to next nesting level
960                levels[++curLevel] = level;
961            else
962                throw ParseException(lineNo, "Unexpected nesting level");
963            canToNextLevel = false;
964        }
965        else if (levels[curLevel] > level)
966        {
967            while (curLevel != UINT_MAX && levels[curLevel] > level)
968                curLevel--;
969            if (curLevel == UINT_MAX)
970                throw ParseException(lineNo, "Indentation smaller than in main level");
971           
972            // pop from previous level
973            if (curLevel < 3)
974            {
975                if (inKernelArgs)
976                {
977                    // leave from kernel args
978                    inKernelArgs = false;
979                    inKernelArg = false;
980                }
981           
982                inKernelCodeProps = false;
983                inKernelAttrs = false;
984            }
985            if (curLevel < 1 && inKernels)
986            {
987                // leave from kernels
988                inKernels = false;
989                inKernel = false;
990            }
991           
992            if (levels[curLevel] != level)
993                throw ParseException(lineNo, "Unexpected nesting level");
994        }
995       
996        oldLineNo = lineNo;
997        if (curLevel == 0)
998        {
999            if (lineNo==1 && ptr+3 <= end && *ptr=='-' && ptr[1]=='-' && ptr[2]=='-' &&
1000                (ptr+3==end || (ptr+3 < end && ptr[3]=='\n')))
1001            {
1002                ptr += 3;
1003                if (ptr!=end)
1004                {
1005                    lineNo++;
1006                    ptr++; // to newline
1007                }
1008                continue; // skip document start
1009            }
1010           
1011            if (ptr+3 <= end && *ptr=='.' && ptr[1]=='.' && ptr[2]=='.' &&
1012                (ptr+3==end || (ptr+3 < end && ptr[3]=='\n')))
1013                break; // end of the document
1014           
1015            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1016                        mainMetadataKeywordsNum, mainMetadataKeywords);
1017           
1018            switch(keyIndex)
1019            {
1020                case ROCMMT_MAIN_KERNELS:
1021                    inKernels = true;
1022                    canToNextLevel = true;
1023                    break;
1024                case ROCMMT_MAIN_PRINTF:
1025                {
1026                    YAMLPrintfVectorConsumer consumer(metadataInfo.printfInfos);
1027                    parseYAMLValArray(ptr, end, lineNo, levels[curLevel], &consumer, true);
1028                    break;
1029                }
1030                case ROCMMT_MAIN_VERSION:
1031                {
1032                    YAMLIntArrayConsumer<uint32_t> consumer(2, metadataInfo.version);
1033                    parseYAMLValArray(ptr, end, lineNo, levels[curLevel], &consumer, true);
1034                    break;
1035                }
1036                default:
1037                    skipYAMLValue(ptr, end, lineNo, level);
1038                    break;
1039            }
1040        }
1041       
1042        if (curLevel==1 && inKernels)
1043        {
1044            // enter to kernel level
1045            if (ptr == end || *ptr != '-')
1046                throw ParseException(lineNo, "No '-' before kernel object");
1047            ptr++;
1048            const char* afterMinus = ptr;
1049            skipSpacesToLineEnd(ptr, end);
1050            levels[++curLevel] = level + 1 + ptr-afterMinus;
1051            level = levels[curLevel];
1052            inKernel = true;
1053           
1054            kernels.push_back(ROCmKernelMetadata());
1055            kernels.back().initialize();
1056        }
1057       
1058        if (curLevel==2 && inKernel)
1059        {
1060            // in kernel
1061            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1062                        kernelMetadataKeywordsNum, kernelMetadataKeywords);
1063           
1064            ROCmKernelMetadata& kernel = kernels.back();
1065            switch(keyIndex)
1066            {
1067                case ROCMMT_KERNEL_ARGS:
1068                    inKernelArgs = true;
1069                    canToNextLevel = true;
1070                    kernel.argInfos.clear();
1071                    break;
1072                case ROCMMT_KERNEL_ATTRS:
1073                    inKernelAttrs = true;
1074                    canToNextLevel = true;
1075                    // initialize kernel attributes values
1076                    kernel.reqdWorkGroupSize[0] = 0;
1077                    kernel.reqdWorkGroupSize[1] = 0;
1078                    kernel.reqdWorkGroupSize[2] = 0;
1079                    kernel.workGroupSizeHint[0] = 0;
1080                    kernel.workGroupSizeHint[1] = 0;
1081                    kernel.workGroupSizeHint[2] = 0;
1082                    kernel.runtimeHandle.clear();
1083                    kernel.vecTypeHint.clear();
1084                    break;
1085                case ROCMMT_KERNEL_CODEPROPS:
1086                    // initialize CodeProps values
1087                    kernel.kernargSegmentSize = BINGEN64_DEFAULT;
1088                    kernel.groupSegmentFixedSize = BINGEN64_DEFAULT;
1089                    kernel.privateSegmentFixedSize = BINGEN64_DEFAULT;
1090                    kernel.kernargSegmentAlign = BINGEN64_DEFAULT;
1091                    kernel.wavefrontSize = BINGEN_DEFAULT;
1092                    kernel.sgprsNum = BINGEN_DEFAULT;
1093                    kernel.vgprsNum = BINGEN_DEFAULT;
1094                    kernel.spilledSgprs = BINGEN_NOTSUPPLIED;
1095                    kernel.spilledVgprs = BINGEN_NOTSUPPLIED;
1096                    kernel.maxFlatWorkGroupSize = BINGEN64_DEFAULT;
1097                    kernel.fixedWorkGroupSize[0] = 0;
1098                    kernel.fixedWorkGroupSize[1] = 0;
1099                    kernel.fixedWorkGroupSize[2] = 0;
1100                    inKernelCodeProps = true;
1101                    canToNextLevel = true;
1102                    break;
1103                case ROCMMT_KERNEL_LANGUAGE:
1104                    kernel.language = parseYAMLStringValue(ptr, end, lineNo, level, true);
1105                    break;
1106                case ROCMMT_KERNEL_LANGUAGE_VERSION:
1107                {
1108                    YAMLIntArrayConsumer<uint32_t> consumer(2, kernel.langVersion);
1109                    parseYAMLValArray(ptr, end, lineNo, levels[curLevel], &consumer);
1110                    break;
1111                }
1112                case ROCMMT_KERNEL_NAME:
1113                    kernel.name = parseYAMLStringValue(ptr, end, lineNo, level, true);
1114                    break;
1115                case ROCMMT_KERNEL_SYMBOLNAME:
1116                    kernel.symbolName = parseYAMLStringValue(ptr, end, lineNo, level, true);
1117                    break;
1118                default:
1119                    skipYAMLValue(ptr, end, lineNo, level);
1120                    break;
1121            }
1122        }
1123       
1124        if (curLevel==3 && inKernelAttrs)
1125        {
1126            // in kernel attributes
1127            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1128                        kernelAttrMetadataKeywordsNum, kernelAttrMetadataKeywords);
1129           
1130            ROCmKernelMetadata& kernel = kernels.back();
1131            switch(keyIndex)
1132            {
1133                case ROCMMT_ATTRS_REQD_WORK_GROUP_SIZE:
1134                {
1135                    YAMLIntArrayConsumer<cxuint> consumer(3, kernel.reqdWorkGroupSize);
1136                    parseYAMLValArray(ptr, end, lineNo, level, &consumer);
1137                    break;
1138                }
1139                case ROCMMT_ATTRS_RUNTIME_HANDLE:
1140                    kernel.runtimeHandle = parseYAMLStringValue(
1141                                ptr, end, lineNo, level, true);
1142                    break;
1143                case ROCMMT_ATTRS_VECTYPEHINT:
1144                    kernel.vecTypeHint = parseYAMLStringValue(
1145                                ptr, end, lineNo, level, true);
1146                    break;
1147                case ROCMMT_ATTRS_WORK_GROUP_SIZE_HINT:
1148                {
1149                    YAMLIntArrayConsumer<cxuint> consumer(3, kernel.workGroupSizeHint);
1150                    parseYAMLValArray(ptr, end, lineNo, level, &consumer, true);
1151                    break;
1152                }
1153                default:
1154                    skipYAMLValue(ptr, end, lineNo, level);
1155                    break;
1156            }
1157        }
1158       
1159        if (curLevel==3 && inKernelCodeProps)
1160        {
1161            // in kernel codeProps
1162            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1163                        kernelCodePropsKeywordsNum, kernelCodePropsKeywords);
1164           
1165            ROCmKernelMetadata& kernel = kernels.back();
1166            switch(keyIndex)
1167            {
1168                case ROCMMT_CODEPROPS_FIXED_WORK_GROUP_SIZE:
1169                {
1170                    YAMLIntArrayConsumer<cxuint> consumer(3, kernel.fixedWorkGroupSize);
1171                    parseYAMLValArray(ptr, end, lineNo, level, &consumer);
1172                    break;
1173                }
1174                case ROCMMT_CODEPROPS_GROUP_SEGMENT_FIXED_SIZE:
1175                    kernel.groupSegmentFixedSize =
1176                                parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1177                    break;
1178                case ROCMMT_CODEPROPS_KERNARG_SEGMENT_ALIGN:
1179                    kernel.kernargSegmentAlign =
1180                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1181                    break;
1182                case ROCMMT_CODEPROPS_KERNARG_SEGMENT_SIZE:
1183                    kernel.kernargSegmentSize =
1184                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1185                    break;
1186                case ROCMMT_CODEPROPS_MAX_FLAT_WORK_GROUP_SIZE:
1187                    kernel.maxFlatWorkGroupSize =
1188                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1189                    break;
1190                case ROCMMT_CODEPROPS_NUM_SGPRS:
1191                    kernel.sgprsNum = parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1192                    break;
1193                case ROCMMT_CODEPROPS_NUM_SPILLED_SGPRS:
1194                    kernel.spilledSgprs =
1195                            parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1196                    break;
1197                case ROCMMT_CODEPROPS_NUM_SPILLED_VGPRS:
1198                    kernel.spilledVgprs =
1199                            parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1200                    break;
1201                case ROCMMT_CODEPROPS_NUM_VGPRS:
1202                    kernel.vgprsNum = parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1203                    break;
1204                case ROCMMT_CODEPROPS_PRIVATE_SEGMENT_FIXED_SIZE:
1205                    kernel.privateSegmentFixedSize =
1206                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1207                    break;
1208                case ROCMMT_CODEPROPS_WAVEFRONT_SIZE:
1209                    kernel.wavefrontSize =
1210                            parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1211                    break;
1212                default:
1213                    skipYAMLValue(ptr, end, lineNo, level);
1214                    break;
1215            }
1216        }
1217       
1218        if (curLevel==3 && inKernelArgs)
1219        {
1220            // enter to kernel argument level
1221            if (ptr == end || *ptr != '-')
1222                throw ParseException(lineNo, "No '-' before argument object");
1223            ptr++;
1224            const char* afterMinus = ptr;
1225            skipSpacesToLineEnd(ptr, end);
1226            levels[++curLevel] = level + 1 + ptr-afterMinus;
1227            level = levels[curLevel];
1228            inKernelArg = true;
1229           
1230            kernels.back().argInfos.push_back(ROCmKernelArgInfo{});
1231        }
1232       
1233        if (curLevel==4 && inKernelArg)
1234        {
1235            // in kernel argument
1236            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1237                        kernelArgInfosKeywordsNum, kernelArgInfosKeywords);
1238           
1239            ROCmKernelArgInfo& kernelArg = kernels.back().argInfos.back();
1240           
1241            size_t valLineNo = lineNo;
1242            switch(keyIndex)
1243            {
1244                case ROCMMT_ARGS_ACCQUAL:
1245                case ROCMMT_ARGS_ACTUALACCQUAL:
1246                {
1247                    const std::string acc = trimStrSpaces(parseYAMLStringValue(
1248                                    ptr, end, lineNo, level, true));
1249                    size_t accIndex = 0;
1250                    for (; accIndex < 6; accIndex++)
1251                        if (::strcmp(rocmAccessQualifierTbl[accIndex], acc.c_str())==0)
1252                            break;
1253                    if (accIndex == 4)
1254                        throw ParseException(lineNo, "Wrong access qualifier");
1255                    if (keyIndex == ROCMMT_ARGS_ACCQUAL)
1256                        kernelArg.accessQual = ROCmAccessQual(accIndex);
1257                    else
1258                        kernelArg.actualAccessQual = ROCmAccessQual(accIndex);
1259                    break;
1260                }
1261                case ROCMMT_ARGS_ADDRSPACEQUAL:
1262                {
1263                    const std::string aspace = trimStrSpaces(parseYAMLStringValue(
1264                                    ptr, end, lineNo, level, true));
1265                    size_t aspaceIndex = 0;
1266                    for (; aspaceIndex < 6; aspaceIndex++)
1267                        if (::strcmp(rocmAddrSpaceTypesTbl[aspaceIndex],
1268                                    aspace.c_str())==0)
1269                            break;
1270                    if (aspaceIndex == 6)
1271                        throw ParseException(valLineNo, "Wrong address space");
1272                    kernelArg.addressSpace = ROCmAddressSpace(aspaceIndex+1);
1273                    break;
1274                }
1275                case ROCMMT_ARGS_ALIGN:
1276                    kernelArg.align = parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1277                    break;
1278                case ROCMMT_ARGS_ISCONST:
1279                    kernelArg.isConst = parseYAMLBoolValue(ptr, end, lineNo, true);
1280                    break;
1281                case ROCMMT_ARGS_ISPIPE:
1282                    kernelArg.isPipe = parseYAMLBoolValue(ptr, end, lineNo, true);
1283                    break;
1284                case ROCMMT_ARGS_ISRESTRICT:
1285                    kernelArg.isRestrict = parseYAMLBoolValue(ptr, end, lineNo, true);
1286                    break;
1287                case ROCMMT_ARGS_ISVOLATILE:
1288                    kernelArg.isVolatile = parseYAMLBoolValue(ptr, end, lineNo, true);
1289                    break;
1290                case ROCMMT_ARGS_NAME:
1291                    kernelArg.name = parseYAMLStringValue(ptr, end, lineNo, level, true);
1292                    break;
1293                case ROCMMT_ARGS_POINTEE_ALIGN:
1294                    kernelArg.pointeeAlign =
1295                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1296                    break;
1297                case ROCMMT_ARGS_SIZE:
1298                    kernelArg.size = parseYAMLIntValue<uint64_t>(ptr, end, lineNo);
1299                    break;
1300                case ROCMMT_ARGS_TYPENAME:
1301                    kernelArg.typeName =
1302                                parseYAMLStringValue(ptr, end, lineNo, level, true);
1303                    break;
1304                case ROCMMT_ARGS_VALUEKIND:
1305                {
1306                    const std::string vkind = trimStrSpaces(parseYAMLStringValue(
1307                                ptr, end, lineNo, level, true));
1308                    const size_t vkindIndex = binaryMapFind(rocmValueKindNamesMap,
1309                            rocmValueKindNamesMap + rocmValueKindNamesNum, vkind.c_str(),
1310                            CStringLess()) - rocmValueKindNamesMap;
1311                    // if unknown kind
1312                    if (vkindIndex == rocmValueKindNamesNum)
1313                        throw ParseException(valLineNo, "Wrong argument value kind");
1314                    kernelArg.valueKind = rocmValueKindNamesMap[vkindIndex].second;
1315                    break;
1316                }
1317                case ROCMMT_ARGS_VALUETYPE:
1318                {
1319                    const std::string vtype = trimStrSpaces(parseYAMLStringValue(
1320                                    ptr, end, lineNo, level, true));
1321                    const size_t vtypeIndex = binaryMapFind(rocmValueTypeNamesMap,
1322                            rocmValueTypeNamesMap + rocmValueTypeNamesNum, vtype.c_str(),
1323                            CStringLess()) - rocmValueTypeNamesMap;
1324                    // if unknown type
1325                    if (vtypeIndex == rocmValueTypeNamesNum)
1326                        throw ParseException(valLineNo, "Wrong argument value type");
1327                    kernelArg.valueType = rocmValueTypeNamesMap[vtypeIndex].second;
1328                    break;
1329                }
1330                default:
1331                    skipYAMLValue(ptr, end, lineNo, level);
1332                    break;
1333            }
1334        }
1335    }
1336}
1337
1338void ROCmMetadata::parse(size_t metadataSize, const char* metadata)
1339{
1340    parseROCmMetadata(metadataSize, metadata, *this);
1341}
1342
1343/*
1344 * ROCm binary reader and generator
1345 */
1346
1347/* TODO: add support for various kernel code offset (now only 256 is supported) */
1348
1349ROCmBinary::ROCmBinary(size_t binaryCodeSize, cxbyte* binaryCode, Flags creationFlags)
1350        : ElfBinary64(binaryCodeSize, binaryCode, creationFlags),
1351          regionsNum(0), codeSize(0), code(nullptr),
1352          globalDataSize(0), globalData(nullptr), metadataSize(0), metadata(nullptr),
1353          newBinFormat(false)
1354{
1355    cxuint textIndex = SHN_UNDEF;
1356    try
1357    { textIndex = getSectionIndex(".text"); }
1358    catch(const Exception& ex)
1359    { } // ignore failed
1360    uint64_t codeOffset = 0;
1361    // find '.text' section
1362    if (textIndex!=SHN_UNDEF)
1363    {
1364        code = getSectionContent(textIndex);
1365        const Elf64_Shdr& textShdr = getSectionHeader(textIndex);
1366        codeSize = ULEV(textShdr.sh_size);
1367        codeOffset = ULEV(textShdr.sh_offset);
1368    }
1369   
1370    cxuint rodataIndex = SHN_UNDEF;
1371    try
1372    { rodataIndex = getSectionIndex(".rodata"); }
1373    catch(const Exception& ex)
1374    { } // ignore failed
1375    // find '.text' section
1376    if (rodataIndex!=SHN_UNDEF)
1377    {
1378        globalData = getSectionContent(rodataIndex);
1379        const Elf64_Shdr& rodataShdr = getSectionHeader(rodataIndex);
1380        globalDataSize = ULEV(rodataShdr.sh_size);
1381    }
1382   
1383    cxuint gpuConfigIndex = SHN_UNDEF;
1384    try
1385    { gpuConfigIndex = getSectionIndex(".AMDGPU.config"); }
1386    catch(const Exception& ex)
1387    { } // ignore failed
1388    newBinFormat = (gpuConfigIndex == SHN_UNDEF);
1389   
1390    cxuint relaDynIndex = SHN_UNDEF;
1391    try
1392    { relaDynIndex = getSectionIndex(".rela.dyn"); }
1393    catch(const Exception& ex)
1394    { } // ignore failed
1395   
1396    cxuint gotIndex = SHN_UNDEF;
1397    try
1398    { gotIndex = getSectionIndex(".got"); }
1399    catch(const Exception& ex)
1400    { } // ignore failed
1401   
1402    // counts regions (symbol or kernel)
1403    regionsNum = 0;
1404    const size_t symbolsNum = getSymbolsNum();
1405    for (size_t i = 0; i < symbolsNum; i++)
1406    {
1407        // count regions number
1408        const Elf64_Sym& sym = getSymbol(i);
1409        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
1410        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
1411        if (ULEV(sym.st_shndx)==textIndex &&
1412            (symType==STT_GNU_IFUNC || symType==STT_FUNC ||
1413                (bind==STB_GLOBAL && symType==STT_OBJECT)))
1414            regionsNum++;
1415    }
1416    if (code==nullptr && regionsNum!=0)
1417        throw BinException("No code if regions number is not zero");
1418    regions.reset(new ROCmRegion[regionsNum]);
1419    size_t j = 0;
1420    typedef std::pair<uint64_t, size_t> RegionOffsetEntry;
1421    std::unique_ptr<RegionOffsetEntry[]> symOffsets(new RegionOffsetEntry[regionsNum]);
1422   
1423    // get regions info
1424    for (size_t i = 0; i < symbolsNum; i++)
1425    {
1426        const Elf64_Sym& sym = getSymbol(i);
1427        if (ULEV(sym.st_shndx)!=textIndex)
1428            continue;   // if not in '.text' section
1429        const size_t value = ULEV(sym.st_value);
1430        if (value < codeOffset)
1431            throw BinException("Region offset is too small!");
1432        const size_t size = ULEV(sym.st_size);
1433       
1434        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
1435        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
1436        if (symType==STT_GNU_IFUNC || symType==STT_FUNC ||
1437                (bind==STB_GLOBAL && symType==STT_OBJECT))
1438        {
1439            ROCmRegionType type = ROCmRegionType::DATA;
1440            // if kernel
1441            if (symType==STT_GNU_IFUNC) 
1442                type = ROCmRegionType::KERNEL;
1443            // if function kernel
1444            else if (symType==STT_FUNC)
1445                type = ROCmRegionType::FKERNEL;
1446            symOffsets[j] = std::make_pair(value, j);
1447            if (type!=ROCmRegionType::DATA && value+0x100 > codeOffset+codeSize)
1448                throw BinException("Kernel or code offset is too big!");
1449            regions[j++] = { getSymbolName(i), size, value, type };
1450        }
1451    }
1452    // sort regions by offset
1453    std::sort(symOffsets.get(), symOffsets.get()+regionsNum,
1454            [](const RegionOffsetEntry& a, const RegionOffsetEntry& b)
1455            { return a.first < b.first; });
1456    // checking distance between regions
1457    for (size_t i = 1; i <= regionsNum; i++)
1458    {
1459        size_t end = (i<regionsNum) ? symOffsets[i].first : codeOffset+codeSize;
1460        ROCmRegion& region = regions[symOffsets[i-1].second];
1461        if (region.type==ROCmRegionType::KERNEL && symOffsets[i-1].first+0x100 > end)
1462            throw BinException("Kernel size is too small!");
1463       
1464        const size_t regSize = end - symOffsets[i-1].first;
1465        if (region.size==0)
1466            region.size = regSize;
1467        else
1468            region.size = std::min(regSize, region.size);
1469    }
1470   
1471    // load got symbols
1472    if (relaDynIndex != SHN_UNDEF && gotIndex != SHN_UNDEF)
1473    {
1474        const Elf64_Shdr& relaShdr = getSectionHeader(relaDynIndex);
1475        const Elf64_Shdr& gotShdr = getSectionHeader(gotIndex);
1476       
1477        size_t relaEntrySize = ULEV(relaShdr.sh_entsize);
1478        if (relaEntrySize==0)
1479            relaEntrySize = sizeof(Elf64_Rela);
1480        const size_t relaEntriesNum = ULEV(relaShdr.sh_size)/relaEntrySize;
1481        const size_t gotEntriesNum = ULEV(gotShdr.sh_size) >> 3;
1482        if (gotEntriesNum != relaEntriesNum)
1483            throw BinException("RelaDyn entries number and GOT entries "
1484                        "number doesn't match!");
1485       
1486        // initialize GOT symbols table
1487        gotSymbols.resize(gotEntriesNum);
1488        const cxbyte* relaDyn = getSectionContent(relaDynIndex);
1489        for (size_t i = 0; i < relaEntriesNum; i++)
1490        {
1491            const Elf64_Rela& rela = *reinterpret_cast<const Elf64_Rela*>(
1492                            relaDyn + relaEntrySize*i);
1493            // check rela entry fields
1494            if (ULEV(rela.r_offset) != ULEV(gotShdr.sh_offset) + i*8)
1495                throw BinException("Wrong dyn relocation offset");
1496            if (ULEV(rela.r_addend) != 0ULL)
1497                throw BinException("Wrong dyn relocation addend");
1498            size_t symIndex = ELF64_R_SYM(ULEV(rela.r_info));
1499            if (symIndex >= getDynSymbolsNum())
1500                throw BinException("Dyn relocation symbol index out of range");
1501            // just set in gotSymbols
1502            gotSymbols[i] = symIndex;
1503        }
1504    }
1505   
1506    // get metadata
1507    const size_t notesSize = getNotesSize();
1508    const cxbyte* noteContent = (const cxbyte*)getNotes();
1509   
1510    for (size_t offset = 0; offset < notesSize; )
1511    {
1512        const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
1513        size_t namesz = ULEV(nhdr->n_namesz);
1514        size_t descsz = ULEV(nhdr->n_descsz);
1515        if (usumGt(offset, namesz+descsz, notesSize))
1516            throw BinException("Note offset+size out of range");
1517       
1518        if (namesz==4 &&
1519            ::strcmp((const char*)noteContent+offset+ sizeof(Elf64_Nhdr), "AMD")==0)
1520        {
1521            const uint32_t noteType = ULEV(nhdr->n_type);
1522            if (noteType == 0xa)
1523            {
1524                metadata = (char*)(noteContent+offset+sizeof(Elf64_Nhdr) + 4);
1525                metadataSize = descsz;
1526            }
1527            else if (noteType == 0xb)
1528                target.assign((char*)(noteContent+offset+sizeof(Elf64_Nhdr) + 4), descsz);
1529        }
1530        size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
1531        offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
1532    }
1533   
1534    if (hasRegionMap())
1535    {
1536        // create region map
1537        regionsMap.resize(regionsNum);
1538        for (size_t i = 0; i < regionsNum; i++)
1539            regionsMap[i] = std::make_pair(regions[i].regionName, i);
1540        // sort region map
1541        mapSort(regionsMap.begin(), regionsMap.end());
1542    }
1543   
1544    if ((creationFlags & ROCMBIN_CREATE_METADATAINFO) != 0 &&
1545        metadata != nullptr && metadataSize != 0)
1546    {
1547        metadataInfo.reset(new ROCmMetadata());
1548        parseROCmMetadata(metadataSize, metadata, *metadataInfo);
1549       
1550        if (hasKernelInfoMap())
1551        {
1552            const std::vector<ROCmKernelMetadata>& kernels = metadataInfo->kernels;
1553            kernelInfosMap.resize(kernels.size());
1554            for (size_t i = 0; i < kernelInfosMap.size(); i++)
1555                kernelInfosMap[i] = std::make_pair(kernels[i].name, i);
1556            // sort region map
1557            mapSort(kernelInfosMap.begin(), kernelInfosMap.end());
1558        }
1559    }
1560}
1561
1562/// determint GPU device from ROCm notes
1563GPUDeviceType ROCmBinary::determineGPUDeviceType(uint32_t& outArchMinor,
1564                     uint32_t& outArchStepping) const
1565{
1566    uint32_t archMajor = 0;
1567    uint32_t archMinor = 0;
1568    uint32_t archStepping = 0;
1569   
1570    {
1571        const cxbyte* noteContent = (const cxbyte*)getNotes();
1572        if (noteContent==nullptr)
1573            throw BinException("Missing notes in inner binary!");
1574        size_t notesSize = getNotesSize();
1575        // find note about AMDGPU
1576        for (size_t offset = 0; offset < notesSize; )
1577        {
1578            const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
1579            size_t namesz = ULEV(nhdr->n_namesz);
1580            size_t descsz = ULEV(nhdr->n_descsz);
1581            if (usumGt(offset, namesz+descsz, notesSize))
1582                throw BinException("Note offset+size out of range");
1583            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
1584                ::strcmp((const char*)noteContent+offset+sizeof(Elf64_Nhdr), "AMD")==0)
1585            {    // AMDGPU type
1586                const uint32_t* content = (const uint32_t*)
1587                        (noteContent+offset+sizeof(Elf64_Nhdr) + 4);
1588                archMajor = ULEV(content[1]);
1589                archMinor = ULEV(content[2]);
1590                archStepping = ULEV(content[3]);
1591            }
1592            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
1593            offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
1594        }
1595    }
1596    // determine device type
1597    GPUDeviceType deviceType = getGPUDeviceTypeFromArchVersion(archMajor, archMinor,
1598                                    archStepping);
1599    outArchMinor = archMinor;
1600    outArchStepping = archStepping;
1601    return deviceType;
1602}
1603
1604const ROCmRegion& ROCmBinary::getRegion(const char* name) const
1605{
1606    RegionMap::const_iterator it = binaryMapFind(regionsMap.begin(),
1607                             regionsMap.end(), name);
1608    if (it == regionsMap.end())
1609        throw BinException("Can't find region name");
1610    return regions[it->second];
1611}
1612
1613const ROCmKernelMetadata& ROCmBinary::getKernelInfo(const char* name) const
1614{
1615    if (!hasMetadataInfo())
1616        throw BinException("Can't find kernel info name");
1617    RegionMap::const_iterator it = binaryMapFind(kernelInfosMap.begin(),
1618                             kernelInfosMap.end(), name);
1619    if (it == kernelInfosMap.end())
1620        throw BinException("Can't find kernel info name");
1621    return metadataInfo->kernels[it->second];
1622}
1623
1624// if ROCm binary
1625bool CLRX::isROCmBinary(size_t binarySize, const cxbyte* binary)
1626{
1627    if (!isElfBinary(binarySize, binary))
1628        return false;
1629    if (binary[EI_CLASS] != ELFCLASS64)
1630        return false;
1631    const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr*>(binary);
1632    if (ULEV(ehdr->e_machine) != 0xe0)
1633        return false;
1634    return true;
1635}
1636
1637
1638void ROCmInput::addEmptyKernel(const char* kernelName)
1639{
1640    symbols.push_back({ kernelName, 0, 0, ROCmRegionType::KERNEL });
1641}
1642
1643/*
1644 * ROCm YAML metadata generator
1645 */
1646
1647static const char* rocmValueKindNames[] =
1648{
1649    "ByValue", "GlobalBuffer", "DynamicSharedPointer", "Sampler", "Image", "Pipe", "Queue",
1650    "HiddenGlobalOffsetX", "HiddenGlobalOffsetY", "HiddenGlobalOffsetZ", "HiddenNone",
1651    "HiddenPrintfBuffer", "HiddenDefaultQueue", "HiddenCompletionAction"
1652};
1653
1654static const char* rocmValueTypeNames[] =
1655{
1656    "Struct", "I8", "U8", "I16", "U16", "F16", "I32", "U32", "F32", "I64", "U64", "F64"
1657};
1658
1659static void genArrayValue(cxuint n, const cxuint* values, std::string& output)
1660{
1661    char numBuf[24];
1662    output += "[ ";
1663    for (cxuint i = 0; i < n; i++)
1664    {
1665        itocstrCStyle(values[i], numBuf, 24);
1666        output += numBuf;
1667        output += (i+1<n) ? ", " : " ]\n";
1668    }
1669}
1670
1671// helper for checking whether value is supplied
1672static inline bool hasValue(cxuint value)
1673{ return value!=BINGEN_NOTSUPPLIED && value!=BINGEN_DEFAULT; }
1674
1675static inline bool hasValue(uint64_t value)
1676{ return value!=BINGEN64_NOTSUPPLIED && value!=BINGEN64_DEFAULT; }
1677
1678// get escaped YAML string if needed, otherwise get this same string
1679static std::string escapeYAMLString(const CString& input)
1680{
1681    bool toEscape = false;
1682    const char* s;
1683    for (s = input.c_str(); *s!=0; s++)
1684    {
1685        cxbyte c = *s;
1686        if (c < 0x20 || c >= 0x80 || c=='*' || c=='&' || c=='!' || c=='@' ||
1687            c=='\'' || c=='\"')
1688            toEscape = true;
1689    }
1690    // if spaces in begin and end
1691    if (isSpace(input[0]) || isDigit(input[0]) ||
1692        (!input.empty() && isSpace(s[-1])))
1693        toEscape = true;
1694   
1695    if (toEscape)
1696    {
1697        std::string out = "'";
1698        out += escapeStringCStyle(s-input.c_str(), input.c_str());
1699        out += "'";
1700        return out;
1701    }
1702    return input.c_str();
1703}
1704
1705static std::string escapePrintfFormat(const std::string& fmt)
1706{
1707    std::string out;
1708    out.reserve(fmt.size());
1709    for (char c: fmt)
1710        if (c!=':')
1711            out.push_back(c);
1712        else
1713            out += "\\72";
1714    return out;
1715}
1716
1717static void generateROCmMetadata(const ROCmMetadata& mdInfo,
1718                    const ROCmKernelConfig** kconfigs, std::string& output)
1719{
1720    output.clear();
1721    char numBuf[24];
1722    output += "---\n";
1723    // version
1724    output += "Version:         ";
1725    if (hasValue(mdInfo.version[0]))
1726        genArrayValue(2, mdInfo.version, output);
1727    else // default
1728        output += "[ 1, 0 ]\n";
1729    if (!mdInfo.printfInfos.empty())
1730        output += "Printf:          \n";
1731    // check print ids uniquness
1732    {
1733        std::unordered_set<cxuint> printfIds;
1734        for (const ROCmPrintfInfo& printfInfo: mdInfo.printfInfos)
1735            if (printfInfo.id!=BINGEN_DEFAULT)
1736                if (!printfIds.insert(printfInfo.id).second)
1737                    throw BinGenException("Duplicate of printf id");
1738        // printfs
1739        uint32_t freePrintfId = 1;
1740        for (const ROCmPrintfInfo& printfInfo: mdInfo.printfInfos)
1741        {
1742            // skip used printfids;
1743            uint32_t printfId = printfInfo.id;
1744            if (printfId == BINGEN_DEFAULT)
1745            {
1746                // skip used printfids
1747                for (; printfIds.find(freePrintfId) != printfIds.end(); ++freePrintfId);
1748                // just use this free printfid
1749                printfId = freePrintfId++;
1750            }
1751           
1752            output += "  - '";
1753            itocstrCStyle(printfId, numBuf, 24);
1754            output += numBuf;
1755            output += ':';
1756            itocstrCStyle(printfInfo.argSizes.size(), numBuf, 24);
1757            output += numBuf;
1758            output += ':';
1759            for (size_t argSize: printfInfo.argSizes)
1760            {
1761                itocstrCStyle(argSize, numBuf, 24);
1762                output += numBuf;
1763                output += ':';
1764            }
1765            // printf format
1766            std::string escapedFmt = escapeStringCStyle(printfInfo.format);
1767            escapedFmt = escapePrintfFormat(escapedFmt);
1768            output += escapedFmt;
1769            output += "'\n";
1770        }
1771    }
1772   
1773    if (!mdInfo.kernels.empty())
1774        output += "Kernels:         \n";
1775    // kernels
1776    for (size_t i = 0; i < mdInfo.kernels.size(); i++)
1777    {
1778        const ROCmKernelMetadata& kernel = mdInfo.kernels[i];
1779        output += "  - Name:            ";
1780        output.append(kernel.name.c_str(), kernel.name.size());
1781        output += "\n    SymbolName:      ";
1782        if (!kernel.symbolName.empty())
1783            output += escapeYAMLString(kernel.symbolName);
1784        else
1785        {
1786            // default is kernel name + '@kd'
1787            std::string symName = kernel.name.c_str();
1788            symName += "@kd";
1789            output += escapeYAMLString(symName);
1790        }
1791        output += "\n";
1792        if (!kernel.language.empty())
1793        {
1794            output += "    Language:        ";
1795            output += escapeYAMLString(kernel.language);
1796            output += "\n";
1797        }
1798        if (kernel.langVersion[0] != BINGEN_NOTSUPPLIED)
1799        {
1800            output += "    LanguageVersion: ";
1801            genArrayValue(2, kernel.langVersion, output);
1802        }
1803        // kernel attributes
1804        if (kernel.reqdWorkGroupSize[0] != 0 || kernel.reqdWorkGroupSize[1] != 0 ||
1805            kernel.reqdWorkGroupSize[2] != 0 ||
1806            kernel.workGroupSizeHint[0] != 0 || kernel.workGroupSizeHint[1] != 0 ||
1807            kernel.workGroupSizeHint[2] != 0 ||
1808            !kernel.vecTypeHint.empty() || !kernel.runtimeHandle.empty())
1809        {
1810            output += "    Attrs:           \n";
1811            if (kernel.workGroupSizeHint[0] != 0 || kernel.workGroupSizeHint[1] != 0 ||
1812                kernel.workGroupSizeHint[2] != 0)
1813            {
1814                output += "      WorkGroupSizeHint: ";
1815                genArrayValue(3, kernel.workGroupSizeHint, output);
1816            }
1817            if (kernel.reqdWorkGroupSize[0] != 0 || kernel.reqdWorkGroupSize[1] != 0 ||
1818                kernel.reqdWorkGroupSize[2] != 0)
1819            {
1820                output += "      ReqdWorkGroupSize: ";
1821                genArrayValue(3, kernel.reqdWorkGroupSize, output);
1822            }
1823            if (!kernel.vecTypeHint.empty())
1824            {
1825                output += "      VecTypeHint:     ";
1826                output += escapeYAMLString(kernel.vecTypeHint);
1827                output += "\n";
1828            }
1829            if (!kernel.runtimeHandle.empty())
1830            {
1831                output += "      RuntimeHandle:   ";
1832                output += escapeYAMLString(kernel.runtimeHandle);
1833                output += "\n";
1834            }
1835        }
1836        // kernel arguments
1837        if (!kernel.argInfos.empty())
1838            output += "    Args:            \n";
1839        for (const ROCmKernelArgInfo& argInfo: kernel.argInfos)
1840        {
1841            output += "      - ";
1842            if (!argInfo.name.empty())
1843            {
1844                output += "Name:            ";
1845                output += escapeYAMLString(argInfo.name);
1846                output += "\n        ";
1847            }
1848            if (!argInfo.typeName.empty())
1849            {
1850                output += "TypeName:        ";
1851                output += escapeYAMLString(argInfo.typeName);
1852                output += "\n        ";
1853            }
1854            output += "Size:            ";
1855            itocstrCStyle(argInfo.size, numBuf, 24);
1856            output += numBuf;
1857            output += "\n        Align:           ";
1858            itocstrCStyle(argInfo.align, numBuf, 24);
1859            output += numBuf;
1860            output += "\n        ValueKind:       ";
1861           
1862            if (argInfo.valueKind > ROCmValueKind::MAX_VALUE)
1863                throw BinGenException("Unknown ValueKind");
1864            output += rocmValueKindNames[cxuint(argInfo.valueKind)];
1865           
1866            if (argInfo.valueType > ROCmValueType::MAX_VALUE)
1867                throw BinGenException("Unknown ValueType");
1868            output += "\n        ValueType:       ";
1869            output += rocmValueTypeNames[cxuint(argInfo.valueType)];
1870            output += "\n";
1871           
1872            if (argInfo.valueKind == ROCmValueKind::DYN_SHARED_PTR)
1873            {
1874                output += "        PointeeAlign:    ";
1875                itocstrCStyle(argInfo.pointeeAlign, numBuf, 24);
1876                output += numBuf;
1877                output += "\n";
1878            }
1879            if (argInfo.valueKind == ROCmValueKind::DYN_SHARED_PTR ||
1880                argInfo.valueKind == ROCmValueKind::GLOBAL_BUFFER)
1881            {
1882                if (argInfo.addressSpace > ROCmAddressSpace::MAX_VALUE ||
1883                    argInfo.addressSpace == ROCmAddressSpace::NONE)
1884                    throw BinGenException("Unknown AddressSpace");
1885                output += "        AddrSpaceQual:   ";
1886                output += rocmAddrSpaceTypesTbl[cxuint(argInfo.addressSpace)-1];
1887                output += "\n";
1888            }
1889            if (argInfo.valueKind == ROCmValueKind::IMAGE ||
1890                argInfo.valueKind == ROCmValueKind::PIPE)
1891            {
1892                if (argInfo.accessQual> ROCmAccessQual::MAX_VALUE)
1893                    throw BinGenException("Unknown AccessQualifier");
1894                output += "        AccQual:         ";
1895                output += rocmAccessQualifierTbl[cxuint(argInfo.accessQual)];
1896                output += "\n";
1897            }
1898            if (argInfo.valueKind == ROCmValueKind::GLOBAL_BUFFER ||
1899                argInfo.valueKind == ROCmValueKind::IMAGE ||
1900                argInfo.valueKind == ROCmValueKind::PIPE)
1901            {
1902                if (argInfo.actualAccessQual> ROCmAccessQual::MAX_VALUE)
1903                    throw BinGenException("Unknown ActualAccessQualifier");
1904                output += "        ActualAccQual:   ";
1905                output += rocmAccessQualifierTbl[cxuint(argInfo.actualAccessQual)];
1906                output += "\n";
1907            }
1908            if (argInfo.isConst)
1909                output += "        IsConst:         true\n";
1910            if (argInfo.isRestrict)
1911                output += "        IsRestrict:      true\n";
1912            if (argInfo.isVolatile)
1913                output += "        IsVolatile:      true\n";
1914            if (argInfo.isPipe)
1915                output += "        IsPipe:          true\n";
1916        }
1917       
1918        // kernel code properties
1919        const ROCmKernelConfig& kconfig = *kconfigs[i];
1920       
1921        output += "    CodeProps:       \n";
1922        output += "      KernargSegmentSize: ";
1923        itocstrCStyle(hasValue(kernel.kernargSegmentSize) ?
1924                kernel.kernargSegmentSize : ULEV(kconfig.kernargSegmentSize),
1925                numBuf, 24);
1926        output += numBuf;
1927        output += "\n      GroupSegmentFixedSize: ";
1928        itocstrCStyle(hasValue(kernel.groupSegmentFixedSize) ?
1929                kernel.groupSegmentFixedSize :
1930                uint64_t(ULEV(kconfig.workgroupGroupSegmentSize)),
1931                numBuf, 24);
1932        output += numBuf;
1933        output += "\n      PrivateSegmentFixedSize: ";
1934        itocstrCStyle(hasValue(kernel.privateSegmentFixedSize) ?
1935                kernel.privateSegmentFixedSize :
1936                uint64_t(ULEV(kconfig.workitemPrivateSegmentSize)),
1937                numBuf, 24);
1938        output += numBuf;
1939        output += "\n      KernargSegmentAlign: ";
1940        itocstrCStyle(hasValue(kernel.kernargSegmentAlign) ?
1941                kernel.kernargSegmentAlign :
1942                uint64_t(1ULL<<kconfig.kernargSegmentAlignment),
1943                numBuf, 24);
1944        output += numBuf;
1945        output += "\n      WavefrontSize:   ";
1946        itocstrCStyle(hasValue(kernel.wavefrontSize) ? kernel.wavefrontSize :
1947                cxuint(1U<<kconfig.wavefrontSize), numBuf, 24);
1948        output += numBuf;
1949        output += "\n      NumSGPRs:        ";
1950        itocstrCStyle(hasValue(kernel.sgprsNum) ? kernel.sgprsNum :
1951                cxuint(ULEV(kconfig.wavefrontSgprCount)), numBuf, 24);
1952        output += numBuf;
1953        output += "\n      NumVGPRs:        ";
1954        itocstrCStyle(hasValue(kernel.vgprsNum) ? kernel.vgprsNum :
1955                cxuint(ULEV(kconfig.workitemVgprCount)), numBuf, 24);
1956        output += numBuf;
1957        // spilled registers
1958        if (hasValue(kernel.spilledSgprs))
1959        {
1960            output += "\n      NumSpilledSGPRs: ";
1961            itocstrCStyle(kernel.spilledSgprs, numBuf, 24);
1962            output += numBuf;
1963        }
1964        if (hasValue(kernel.spilledVgprs))
1965        {
1966            output += "\n      NumSpilledVGPRs: ";
1967            itocstrCStyle(kernel.spilledVgprs, numBuf, 24);
1968            output += numBuf;
1969        }
1970        output += "\n      MaxFlatWorkGroupSize: ";
1971        itocstrCStyle(hasValue(kernel.maxFlatWorkGroupSize) ?
1972                    kernel.maxFlatWorkGroupSize : uint64_t(256), numBuf, 24);
1973        output += numBuf;
1974        output += "\n";
1975        if (kernel.fixedWorkGroupSize[0] != 0 || kernel.fixedWorkGroupSize[1] != 0 ||
1976            kernel.fixedWorkGroupSize[2] != 0)
1977        {
1978            output += "      FixedWorkGroupSize:   ";
1979            genArrayValue(3, kernel.fixedWorkGroupSize, output);
1980        }
1981    }
1982    output += "...\n";
1983}
1984
1985/* ROCm section generators */
1986
1987class CLRX_INTERNAL ROCmGotGen: public ElfRegionContent
1988{
1989private:
1990    const ROCmInput* input;
1991public:
1992    explicit ROCmGotGen(const ROCmInput* _input) : input(_input)
1993    { }
1994   
1995    void operator()(FastOutputBuffer& fob) const
1996    {
1997        fob.fill(input->gotSymbols.size()*8, 0);
1998    }
1999};
2000
2001class CLRX_INTERNAL ROCmRelaDynGen: public ElfRegionContent
2002{
2003private:
2004    size_t gotOffset;
2005    const ROCmInput* input;
2006public:
2007    explicit ROCmRelaDynGen(const ROCmInput* _input) : gotOffset(0), input(_input)
2008    { }
2009   
2010    void setGotOffset(size_t _gotOffset)
2011    { gotOffset = _gotOffset; }
2012   
2013    void operator()(FastOutputBuffer& fob) const
2014    {
2015        for (size_t i = 0; i < input->gotSymbols.size(); i++)
2016        {
2017            size_t symIndex = input->gotSymbols[i];
2018            Elf64_Rela rela{};
2019            SLEV(rela.r_offset, gotOffset + 8*i);
2020            SLEV(rela.r_info, ELF64_R_INFO(symIndex + 1, 3));
2021            rela.r_addend = 0;
2022            fob.writeObject(rela);
2023        }
2024    }
2025};
2026
2027/*
2028 * ROCm Binary Generator
2029 */
2030
2031ROCmBinGenerator::ROCmBinGenerator() : manageable(false), input(nullptr)
2032{ }
2033
2034ROCmBinGenerator::ROCmBinGenerator(const ROCmInput* rocmInput)
2035        : manageable(false), input(rocmInput), rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
2036{ }
2037
2038ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
2039        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
2040        size_t globalDataSize, const cxbyte* globalData,
2041        const std::vector<ROCmSymbolInput>& symbols) :
2042        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
2043{
2044    input = new ROCmInput{ deviceType, archMinor, archStepping, 0, false,
2045            globalDataSize, globalData, symbols, codeSize, code };
2046}
2047
2048ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
2049        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
2050        size_t globalDataSize, const cxbyte* globalData,
2051        std::vector<ROCmSymbolInput>&& symbols) :
2052        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
2053{
2054    input = new ROCmInput{ deviceType, archMinor, archStepping, 0, false,
2055            globalDataSize, globalData, std::move(symbols), codeSize, code };
2056}
2057
2058ROCmBinGenerator::~ROCmBinGenerator()
2059{
2060    if (manageable)
2061        delete input;
2062    if (rocmGotGen!=nullptr)
2063        delete (ROCmGotGen*)rocmGotGen;
2064    if (rocmRelaDynGen!=nullptr)
2065        delete (ROCmRelaDynGen*)rocmRelaDynGen;
2066}
2067
2068void ROCmBinGenerator::setInput(const ROCmInput* input)
2069{
2070    if (manageable)
2071        delete input;
2072    manageable = false;
2073    this->input = input;
2074}
2075
2076// ELF notes contents
2077static const cxbyte noteDescType1[8] =
2078{ 2, 0, 0, 0, 1, 0, 0, 0 };
2079
2080static const cxbyte noteDescType3[27] =
2081{ 4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2082  'A', 'M', 'D', 0, 'A', 'M', 'D', 'G', 'P', 'U', 0 };
2083
2084static inline void addMainSectionToTable(cxuint& sectionsNum, uint16_t* builtinTable,
2085                cxuint elfSectId)
2086{ builtinTable[elfSectId - ELFSECTID_START] = sectionsNum++; }
2087
2088void ROCmBinGenerator::prepareBinaryGen()
2089{
2090    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(input->deviceType,
2091                GPUArchVersionTable::ROCM);
2092    if (input->archMinor!=UINT32_MAX)
2093        amdGpuArchValues.minor = input->archMinor;
2094    if (input->archStepping!=UINT32_MAX)
2095        amdGpuArchValues.stepping = input->archStepping;
2096   
2097    comment = "CLRX ROCmBinGenerator " CLRX_VERSION;
2098    commentSize = ::strlen(comment);
2099    if (input->comment!=nullptr)
2100    {
2101        // if comment, store comment section
2102        comment = input->comment;
2103        commentSize = input->commentSize;
2104        if (commentSize==0)
2105            commentSize = ::strlen(comment);
2106    }
2107   
2108    uint32_t eflags = input->newBinFormat ? 2 : 0;
2109    if (input->eflags != BINGEN_DEFAULT)
2110        eflags = input->eflags;
2111   
2112    std::fill(mainBuiltinSectTable,
2113              mainBuiltinSectTable + ROCMSECTID_MAX-ELFSECTID_START+1, SHN_UNDEF);
2114    mainSectionsNum = 1;
2115   
2116    // generate main builtin section table (for section id translation)
2117    if (input->newBinFormat)
2118        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
2119    if (input->globalData != nullptr)
2120        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_RODATA);
2121    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSYM);
2122    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_HASH);
2123    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSTR);
2124    if (!input->gotSymbols.empty())
2125        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_RELADYN);
2126    const cxuint execProgHeaderRegionIndex = mainSectionsNum;
2127    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_TEXT);
2128    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_DYNAMIC);
2129    if (!input->gotSymbols.empty())
2130        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GOT);
2131    if (!input->newBinFormat)
2132    {
2133        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
2134        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GPUCONFIG);
2135    }
2136    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_COMMENT);
2137    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SYMTAB);
2138    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SHSTRTAB);
2139    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_STRTAB);
2140   
2141    elfBinGen64.reset(new ElfBinaryGen64({ 0U, 0U, 0x40, 0, ET_DYN, 0xe0, EV_CURRENT,
2142            cxuint(input->newBinFormat ? execProgHeaderRegionIndex : UINT_MAX), 0, eflags },
2143            true, true, true, PHREGION_FILESTART));
2144   
2145    static const int32_t dynTags[] = {
2146        DT_SYMTAB, DT_SYMENT, DT_STRTAB, DT_STRSZ, DT_HASH };
2147    elfBinGen64->addDynamics(sizeof(dynTags)/sizeof(int32_t), dynTags);
2148   
2149    // elf program headers
2150    elfBinGen64->addProgramHeader({ PT_PHDR, PF_R, 0, 1,
2151                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
2152    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R, PHREGION_FILESTART,
2153                    execProgHeaderRegionIndex,
2154                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 0x1000 });
2155    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_X, execProgHeaderRegionIndex, 1,
2156                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
2157    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_W, execProgHeaderRegionIndex+1,
2158                    cxuint(1 + (!input->gotSymbols.empty())),
2159                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
2160    elfBinGen64->addProgramHeader({ PT_DYNAMIC, PF_R|PF_W, execProgHeaderRegionIndex+1, 1,
2161                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 8 });
2162    elfBinGen64->addProgramHeader({ PT_GNU_RELRO, PF_R, execProgHeaderRegionIndex+1,
2163                    cxuint(1 + (!input->gotSymbols.empty())),
2164                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 1 });
2165    elfBinGen64->addProgramHeader({ PT_GNU_STACK, PF_R|PF_W, PHREGION_FILESTART, 0,
2166                    true, 0, 0, 0 });
2167   
2168    if (input->newBinFormat)
2169        // program header for note (new binary format)
2170        elfBinGen64->addProgramHeader({ PT_NOTE, PF_R, 1, 1, true,
2171                    Elf64Types::nobase, Elf64Types::nobase, 0, 4 });
2172   
2173    target = input->target.c_str();
2174    if (target.empty() && !input->targetTripple.empty())
2175    {
2176        target = input->targetTripple.c_str();
2177        char dbuf[20];
2178        snprintf(dbuf, 20, "-gfx%u%u%u", amdGpuArchValues.major, amdGpuArchValues.minor,
2179                 amdGpuArchValues.stepping);
2180        target += dbuf;
2181    }
2182    // elf notes
2183    elfBinGen64->addNote({"AMD", sizeof noteDescType1, noteDescType1, 1U});
2184    noteBuf.reset(new cxbyte[0x1b]);
2185    ::memcpy(noteBuf.get(), noteDescType3, 0x1b);
2186    SULEV(*(uint32_t*)(noteBuf.get()+4), amdGpuArchValues.major);
2187    SULEV(*(uint32_t*)(noteBuf.get()+8), amdGpuArchValues.minor);
2188    SULEV(*(uint32_t*)(noteBuf.get()+12), amdGpuArchValues.stepping);
2189    elfBinGen64->addNote({"AMD", 0x1b, noteBuf.get(), 3U});
2190    if (!target.empty())
2191        elfBinGen64->addNote({"AMD", target.size(), (const cxbyte*)target.c_str(), 0xbU});
2192   
2193    metadataSize = input->metadataSize;
2194    metadata = input->metadata;
2195    if (input->useMetadataInfo)
2196    {
2197        // generate ROCm metadata
2198        std::vector<std::pair<CString, size_t> > symbolIndices(input->symbols.size());
2199        // create sorted indices of symbols by its name
2200        for (size_t k = 0; k < input->symbols.size(); k++)
2201            symbolIndices[k] = std::make_pair(input->symbols[k].symbolName, k);
2202        mapSort(symbolIndices.begin(), symbolIndices.end());
2203       
2204        const size_t mdKernelsNum = input->metadataInfo.kernels.size();
2205        std::unique_ptr<const ROCmKernelConfig*[]> kernelConfigPtrs(
2206                new const ROCmKernelConfig*[mdKernelsNum]);
2207        // generate ROCm kernel config pointers
2208        for (size_t k = 0; k < mdKernelsNum; k++)
2209        {
2210            auto it = binaryMapFind(symbolIndices.begin(), symbolIndices.end(), 
2211                        input->metadataInfo.kernels[k].name);
2212            if (it == symbolIndices.end() ||
2213                (input->symbols[it->second].type != ROCmRegionType::FKERNEL &&
2214                 input->symbols[it->second].type != ROCmRegionType::KERNEL))
2215                throw BinGenException("Kernel in metadata doesn't exists in code");
2216            kernelConfigPtrs[k] = reinterpret_cast<const ROCmKernelConfig*>(
2217                        input->code + input->symbols[it->second].offset);
2218        }
2219        // just generate ROCm metadata from info
2220        generateROCmMetadata(input->metadataInfo, kernelConfigPtrs.get(), metadataStr);
2221        metadataSize = metadataStr.size();
2222        metadata = metadataStr.c_str();
2223    }
2224   
2225    if (metadataSize != 0)
2226        elfBinGen64->addNote({"AMD", metadataSize, (const cxbyte*)metadata, 0xaU});
2227   
2228    /// region and sections
2229    elfBinGen64->addRegion(ElfRegion64::programHeaderTable());
2230    if (input->newBinFormat)
2231        elfBinGen64->addRegion(ElfRegion64::noteSection());
2232    if (input->globalData != nullptr)
2233        elfBinGen64->addRegion(ElfRegion64(input->globalDataSize, input->globalData, 4,
2234                ".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, Elf64Types::nobase));
2235   
2236    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
2237                ".dynsym", SHT_DYNSYM, SHF_ALLOC, 0, BINGEN_DEFAULT, Elf64Types::nobase));
2238    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 4,
2239                ".hash", SHT_HASH, SHF_ALLOC,
2240                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
2241                Elf64Types::nobase));
2242    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".dynstr", SHT_STRTAB,
2243                SHF_ALLOC, 0, 0, Elf64Types::nobase));
2244    if (!input->gotSymbols.empty())
2245    {
2246        ROCmRelaDynGen* sgen = new ROCmRelaDynGen(input);
2247        rocmRelaDynGen = (void*)sgen;
2248        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*sizeof(Elf64_Rela),
2249                sgen, 8, ".rela.dyn", SHT_RELA, SHF_ALLOC,
2250                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
2251                Elf64Types::nobase, sizeof(Elf64_Rela)));
2252    }
2253    // '.text' with alignment=4096
2254    elfBinGen64->addRegion(ElfRegion64(input->codeSize, (const cxbyte*)input->code, 
2255              0x1000, ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 0, 0,
2256              Elf64Types::nobase, 0, false, 256));
2257    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 0x1000,
2258                ".dynamic", SHT_DYNAMIC, SHF_ALLOC|SHF_WRITE,
2259                mainBuiltinSectTable[ELFSECTID_DYNSTR-ELFSECTID_START], 0,
2260                Elf64Types::nobase, 0, false, 8));
2261    if (!input->gotSymbols.empty())
2262    {
2263        ROCmGotGen* sgen = new ROCmGotGen(input);
2264        rocmGotGen = (void*)sgen;
2265        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*8, sgen,
2266                8, ".got", SHT_PROGBITS,
2267                SHF_ALLOC|SHF_WRITE, 0, 0, Elf64Types::nobase));
2268    }
2269    if (!input->newBinFormat)
2270    {
2271        elfBinGen64->addRegion(ElfRegion64::noteSection());
2272        elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1,
2273                    ".AMDGPU.config", SHT_PROGBITS, 0));
2274    }
2275    elfBinGen64->addRegion(ElfRegion64(commentSize, (const cxbyte*)comment, 1, ".comment",
2276              SHT_PROGBITS, SHF_MERGE|SHF_STRINGS, 0, 0, 0, 1));
2277    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
2278                ".symtab", SHT_SYMTAB, 0, 0, BINGEN_DEFAULT));
2279    elfBinGen64->addRegion(ElfRegion64::shstrtabSection());
2280    elfBinGen64->addRegion(ElfRegion64::strtabSection());
2281    elfBinGen64->addRegion(ElfRegion64::sectionHeaderTable());
2282   
2283    /* extra sections */
2284    for (const BinSection& section: input->extraSections)
2285        elfBinGen64->addRegion(ElfRegion64(section, mainBuiltinSectTable,
2286                         ROCMSECTID_MAX, mainSectionsNum));
2287    updateSymbols();
2288    binarySize = elfBinGen64->countSize();
2289   
2290    if (rocmRelaDynGen != nullptr)
2291        ((ROCmRelaDynGen*)rocmRelaDynGen)->setGotOffset(
2292                elfBinGen64->getRegionOffset(
2293                        mainBuiltinSectTable[ROCMSECTID_GOT - ELFSECTID_START]));
2294}
2295
2296void ROCmBinGenerator::updateSymbols()
2297{
2298    elfBinGen64->clearSymbols();
2299    elfBinGen64->clearDynSymbols();
2300    // add symbols (kernels, function kernels and data symbols)
2301    elfBinGen64->addSymbol(ElfSymbol64("_DYNAMIC",
2302                  mainBuiltinSectTable[ROCMSECTID_DYNAMIC-ELFSECTID_START],
2303                  ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE), STV_HIDDEN, true, 0, 0));
2304    const uint16_t textSectIndex = mainBuiltinSectTable[ELFSECTID_TEXT-ELFSECTID_START];
2305    for (const ROCmSymbolInput& symbol: input->symbols)
2306    {
2307        ElfSymbol64 elfsym;
2308        switch (symbol.type)
2309        {
2310            case ROCmRegionType::KERNEL:
2311                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
2312                      ELF64_ST_INFO(STB_GLOBAL, STT_GNU_IFUNC), 0, true,
2313                      symbol.offset, symbol.size);
2314                break;
2315            case ROCmRegionType::FKERNEL:
2316                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
2317                      ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), 0, true,
2318                      symbol.offset, symbol.size);
2319                break;
2320            case ROCmRegionType::DATA:
2321                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
2322                      ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT), 0, true,
2323                      symbol.offset, symbol.size);
2324                break;
2325            default:
2326                break;
2327        }
2328        // add to symbols and dynamic symbols table
2329        elfBinGen64->addSymbol(elfsym);
2330        elfBinGen64->addDynSymbol(elfsym);
2331    }
2332    /* extra symbols */
2333    for (const BinSymbol& symbol: input->extraSymbols)
2334    {
2335        ElfSymbol64 sym(symbol, mainBuiltinSectTable,
2336                         ROCMSECTID_MAX, mainSectionsNum);
2337        elfBinGen64->addSymbol(sym);
2338        elfBinGen64->addDynSymbol(sym);
2339    }
2340}
2341
2342void ROCmBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
2343             Array<cxbyte>* aPtr)
2344{
2345    if (elfBinGen64 == nullptr)
2346        prepareBinaryGen();
2347    /****
2348     * prepare for write binary to output
2349     ****/
2350    std::unique_ptr<std::ostream> outStreamHolder;
2351    std::ostream* os = nullptr;
2352    if (aPtr != nullptr)
2353    {
2354        aPtr->resize(binarySize);
2355        outStreamHolder.reset(
2356                new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
2357        os = outStreamHolder.get();
2358    }
2359    else if (vPtr != nullptr)
2360    {
2361        vPtr->resize(binarySize);
2362        outStreamHolder.reset(new VectorOStream(*vPtr));
2363        os = outStreamHolder.get();
2364    }
2365    else // from argument
2366        os = osPtr;
2367   
2368    const std::ios::iostate oldExceptions = os->exceptions();
2369    try
2370    {
2371    os->exceptions(std::ios::failbit | std::ios::badbit);
2372    /****
2373     * write binary to output
2374     ****/
2375    FastOutputBuffer bos(256, *os);
2376    elfBinGen64->generate(bos);
2377    assert(bos.getWritten() == binarySize);
2378   
2379    if (rocmGotGen != nullptr)
2380    {
2381        delete (ROCmGotGen*)rocmGotGen;
2382        rocmGotGen = nullptr;
2383    }
2384    if (rocmRelaDynGen != nullptr)
2385    {
2386        delete (ROCmGotGen*)rocmRelaDynGen;
2387        rocmRelaDynGen = nullptr;
2388    }
2389    }
2390    catch(...)
2391    {
2392        os->exceptions(oldExceptions);
2393        throw;
2394    }
2395    os->exceptions(oldExceptions);
2396}
2397
2398void ROCmBinGenerator::generate(Array<cxbyte>& array)
2399{
2400    generateInternal(nullptr, nullptr, &array);
2401}
2402
2403void ROCmBinGenerator::generate(std::ostream& os)
2404{
2405    generateInternal(&os, nullptr, nullptr);
2406}
2407
2408void ROCmBinGenerator::generate(std::vector<char>& v)
2409{
2410    generateInternal(nullptr, &v, nullptr);
2411}
Note: See TracBrowser for help on using the repository browser.