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

Last change on this file since 4817 was 4817, checked in by matszpk, 6 months ago

CLRadeonExtender: GCNAsm: Add VOP1 instructions testcases for GFX10. Fixed segfault for new ROCm binary format if STT_FUNC symbols present (accept only real kernel symbols).

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