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

Last change on this file since 3695 was 3695, checked in by matszpk, 23 months ago

CLRadeonExtender: ROCmMetadata: Initialize the kernel attrs and code props after its begin.

File size: 64.4 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 <CLRX/amdbin/ElfBinaries.h>
30#include <CLRX/utils/Utilities.h>
31#include <CLRX/utils/MemAccess.h>
32#include <CLRX/utils/InputOutput.h>
33#include <CLRX/utils/Containers.h>
34#include <CLRX/amdbin/ROCmBinaries.h>
35
36using namespace CLRX;
37
38/*
39 * ROCm metadata YAML parser
40 */
41
42ROCmKernelMetadata::ROCmKernelMetadata() :
43    langVersion{ BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED },
44    reqdWorkGroupSize{ BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED },
45    workGroupSizeHint{ BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED },
46    kernargSegmentSize(BINGEN64_NOTSUPPLIED),
47    groupSegmentFixedSize(BINGEN64_NOTSUPPLIED),
48    privateSegmentFixedSize(BINGEN64_NOTSUPPLIED),
49    kernargSegmentAlign(BINGEN64_NOTSUPPLIED),
50    wavefrontSize(BINGEN_NOTSUPPLIED),
51    sgprsNum(BINGEN_NOTSUPPLIED), vgprsNum(BINGEN_NOTSUPPLIED),
52    maxFlatWorkGroupSize(BINGEN64_NOTSUPPLIED),
53    fixedWorkGroupSize{ BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED, BINGEN_NOTSUPPLIED },
54    spilledSgprs(BINGEN_NOTSUPPLIED),
55    spilledVgprs(BINGEN_NOTSUPPLIED)
56{ }
57
58ROCmMetadata::ROCmMetadata() : version{ 0, 0 }
59{ }
60
61// return trailing spaces
62static size_t skipSpacesAndComments(const char*& ptr, const char* end, size_t& lineNo)
63{
64    const char* lineStart = ptr;
65    while (ptr != end)
66    {
67        lineStart = ptr;
68        while (ptr != end && *ptr!='\n' && isSpace(*ptr)) ptr++;
69        if (ptr == end)
70            break; // end of stream
71        if (*ptr=='#')
72        {
73            // skip comment
74            while (ptr != end && *ptr!='\n') ptr++;
75            if (ptr == end)
76                return 0; // no trailing spaces and end
77        }
78        else if (*ptr!='\n')
79            break; // no comment and no end of line
80        else
81        {
82            ptr++;
83            lineNo++; // next line
84        }
85    }
86    return ptr - lineStart;
87}
88
89static inline void skipSpacesToLineEnd(const char*& ptr, const char* end)
90{
91    while (ptr != end && *ptr!='\n' && isSpace(*ptr)) ptr++;
92}
93
94static void skipSpacesToNextLine(const char*& ptr, const char* end, size_t& lineNo)
95{
96    skipSpacesToLineEnd(ptr, end);
97    if (ptr != end && *ptr != '\n' && *ptr!='#')
98        throw ParseException(lineNo, "Garbages at line");
99    if (ptr != end && *ptr == '#')
100        // skip comment at end of line
101        while (ptr!=end && *ptr!='\n') ptr++;
102    if (ptr!=end)
103    {   // newline
104        ptr++;
105        lineNo++;
106    }
107}
108
109static size_t parseYAMLKey(const char*& ptr, const char* end, size_t lineNo,
110            size_t keywordsNum, const char** keywords)
111{
112    const char* keyPtr = ptr;
113    while (ptr != end && (isAlnum(*ptr) || *ptr=='_')) ptr++;
114    if (keyPtr == end)
115        throw ParseException(lineNo, "Expected key name");
116    const char* keyEnd = ptr;
117    while (ptr != end && *ptr!='\n' && isSpace(*ptr)) ptr++;
118    if (ptr == end || *ptr!=':')
119        throw ParseException(lineNo, "Expected colon");
120    ptr++;
121    const char* afterColon = ptr;
122    skipSpacesToLineEnd(ptr, end);
123    if (afterColon == ptr && ptr != end && *ptr!='\n' && *ptr!='#')
124        // only if not immediate newline or comment
125        throw ParseException(lineNo, "After key and colon must be space");
126    CString keyword(keyPtr, keyEnd);
127    const size_t index = binaryFind(keywords, keywords+keywordsNum,
128                        keyword.c_str(), CStringLess()) - keywords;
129    return index;
130}
131
132template<typename T>
133static T parseYAMLIntValue(const char*& ptr, const char* end, size_t& lineNo,
134                bool singleValue = false)
135{
136    skipSpacesToLineEnd(ptr, end);
137    if (ptr == end || *ptr=='\n')
138        throw ParseException(lineNo, "Expected integer value");
139    T value = 0;
140    try
141    { value = cstrtovCStyle<T>(ptr, end, ptr); }
142    catch(const ParseException& ex)
143    { throw ParseException(lineNo, ex.what()); }
144   
145    if (singleValue)
146        skipSpacesToNextLine(ptr, end, lineNo);
147    return value;
148}
149
150static bool parseYAMLBoolValue(const char*& ptr, const char* end, size_t& lineNo,
151        bool singleValue = false)
152{
153    skipSpacesToLineEnd(ptr, end);
154    if (ptr == end || *ptr=='\n')
155        throw ParseException(lineNo, "Expected boolean value");
156   
157    const char* wordPtr = ptr;
158    while(ptr != end && isAlnum(*ptr)) ptr++;
159    CString word(wordPtr, ptr);
160   
161    bool value = false;
162    bool isSet = false;
163    for (const char* v: { "1", "true", "t", "on", "yes", "y"})
164        if (::strcasecmp(word.c_str(), v) == 0)
165        {
166            isSet = true;
167            value = true;
168            break;
169        }
170    if (!isSet)
171        for (const char* v: { "0", "false", "f", "off", "no", "n"})
172            if (::strcasecmp(word.c_str(), v) == 0)
173            {
174                isSet = true;
175                value = false;
176                break;
177            }
178    if (!isSet)
179        throw ParseException(lineNo, "Is not boolean value");
180   
181    if (singleValue)
182        skipSpacesToNextLine(ptr, end, lineNo);
183    return value;
184}
185
186static std::string trimStrSpaces(const std::string& str)
187{
188    size_t i = 0;
189    const size_t sz = str.size();
190    while (i!=sz && isSpace(str[i])) i++;
191    if (i == sz) return "";
192    size_t j = sz-1;
193    while (j>i && isSpace(str[j])) j--;
194    return str.substr(i, j-i+1);
195}
196
197static std::string parseYAMLString(const char*& linePtr, const char* end,
198            size_t& lineNo)
199{
200    std::string strarray;
201    if (linePtr == end || (*linePtr != '"' && *linePtr != '\''))
202    {
203        while (linePtr != end && !isSpace(*linePtr) && *linePtr != ',') linePtr++;
204        throw ParseException(lineNo, "Expected string");
205    }
206    const char termChar = *linePtr;
207    linePtr++;
208   
209    // main loop, where is character parsing
210    while (linePtr != end && *linePtr != termChar)
211    {
212        if (*linePtr == '\\')
213        {
214            // escape
215            linePtr++;
216            uint16_t value;
217            if (linePtr == end)
218                throw ParseException(lineNo, "Unterminated character of string");
219            if (*linePtr == 'x')
220            {
221                // hex literal
222                linePtr++;
223                if (linePtr == end)
224                    throw ParseException(lineNo, "Unterminated character of string");
225                value = 0;
226                if (isXDigit(*linePtr))
227                    for (; linePtr != end; linePtr++)
228                    {
229                        cxuint digit;
230                        if (*linePtr >= '0' && *linePtr <= '9')
231                            digit = *linePtr-'0';
232                        else if (*linePtr >= 'a' && *linePtr <= 'f')
233                            digit = *linePtr-'a'+10;
234                        else if (*linePtr >= 'A' && *linePtr <= 'F')
235                            digit = *linePtr-'A'+10;
236                        else
237                            break;
238                        value = (value<<4) + digit;
239                    }
240                else
241                    throw ParseException(lineNo, "Expected hexadecimal character code");
242                value &= 0xff;
243            }
244            else if (isODigit(*linePtr))
245            {
246                // octal literal
247                value = 0;
248                for (cxuint i = 0; linePtr != end && i < 3; i++, linePtr++)
249                {
250                    if (!isODigit(*linePtr))
251                        break;
252                    value = (value<<3) + uint64_t(*linePtr-'0');
253                    // checking range
254                    if (value > 255)
255                        throw ParseException(lineNo, "Octal code out of range");
256                }
257            }
258            else
259            {
260                // normal escapes
261                const char c = *linePtr++;
262                switch (c)
263                {
264                    case 'a':
265                        value = '\a';
266                        break;
267                    case 'b':
268                        value = '\b';
269                        break;
270                    case 'r':
271                        value = '\r';
272                        break;
273                    case 'n':
274                        value = '\n';
275                        break;
276                    case 'f':
277                        value = '\f';
278                        break;
279                    case 'v':
280                        value = '\v';
281                        break;
282                    case 't':
283                        value = '\t';
284                        break;
285                    case '\\':
286                        value = '\\';
287                        break;
288                    case '\'':
289                        value = '\'';
290                        break;
291                    case '\"':
292                        value = '\"';
293                        break;
294                    default:
295                        value = c;
296                }
297            }
298            strarray.push_back(value);
299        }
300        else // regular character
301        {
302            if (*linePtr=='\n')
303                lineNo++;
304            strarray.push_back(*linePtr++);
305        }
306    }
307    if (linePtr == end)
308        throw ParseException(lineNo, "Unterminated string");
309    linePtr++;
310    return strarray;
311}
312
313static std::string parseYAMLStringValue(const char*& ptr, const char* end, size_t& lineNo,
314                    cxuint prevIndent, bool singleValue = false, bool blockAccept = true)
315{
316    skipSpacesToLineEnd(ptr, end);
317    if (ptr == end)
318        return "";
319    std::string buf;
320    if (*ptr=='"' || *ptr== '\'')
321        buf = parseYAMLString(ptr, end, lineNo);
322    // otherwise parse stream
323    else if (*ptr == '|' || *ptr == '>')
324    {
325        if (!blockAccept)
326            throw ParseException(lineNo, "Illegal block string start");
327        // multiline
328        bool newLineFold = *ptr=='>';
329        ptr++;
330        skipSpacesToLineEnd(ptr, end);
331        if (ptr!=end && *ptr!='\n')
332            throw ParseException(lineNo, "Garbages at string block");
333        if (ptr == end)
334            return ""; // end
335        lineNo++;
336        ptr++; // skip newline
337        const char* lineStart = ptr;
338        skipSpacesToLineEnd(ptr, end);
339        size_t indent = ptr - lineStart;
340        if (indent <= prevIndent)
341            throw ParseException(lineNo, "Unindented string block");
342       
343        std::string buf;
344        while(ptr != end)
345        {
346            const char* strStart = ptr;
347            while (ptr != end && *ptr!='\n') ptr++;
348            buf.append(strStart, ptr);
349           
350            if (ptr != end) // if new line
351            {
352                lineNo++;
353                ptr++;
354            }
355            else // end of stream
356                break;
357           
358            const char* lineStart = ptr;
359            skipSpacesToLineEnd(ptr, end);
360            bool emptyLines = false;
361            while (size_t(ptr - lineStart) <= indent)
362            {
363                if (ptr != end && *ptr=='\n')
364                {
365                    // empty line
366                    buf.append("\n");
367                    ptr++;
368                    lineNo++;
369                    lineStart = ptr;
370                    skipSpacesToLineEnd(ptr, end);
371                    emptyLines = true;
372                    continue;
373                }
374                // if smaller indent
375                if (size_t(ptr - lineStart) < indent)
376                {
377                    buf.append("\n"); // always add newline at last line
378                    if (ptr != end)
379                        ptr = lineStart;
380                    return buf;
381                }
382                else // if this same and not end of line
383                    break;
384            }
385           
386            if (!emptyLines || !newLineFold)
387                // add missing newline after line with text
388                // only if no emptyLines or no newLineFold
389                buf.append(newLineFold ? " " : "\n");
390            // to indent
391            ptr = lineStart + indent;
392        }
393        return buf;
394    }
395    else
396    {
397        // single line string (unquoted)
398        const char* strStart = ptr;
399        // automatically trim spaces at ends
400        const char* strEnd = ptr;
401        while (ptr != end && *ptr!='\n' && *ptr!='#')
402        {
403            if (!isSpace(*ptr))
404                strEnd = ptr; // to trim at end
405            ptr++;
406        }
407        if (strEnd != end && !isSpace(*strEnd))
408            strEnd++;
409       
410        buf.assign(strStart, strEnd);
411    }
412   
413    if (singleValue)
414        skipSpacesToNextLine(ptr, end, lineNo);
415    return buf;
416}
417
418class CLRX_INTERNAL YAMLElemConsumer
419{
420public:
421    virtual void consume(const char*& ptr, const char* end, size_t& lineNo,
422                cxuint prevIndent, bool singleValue, bool blockAccept) = 0;
423};
424
425static void parseYAMLValArray(const char*& ptr, const char* end, size_t& lineNo,
426            size_t prevIndent, YAMLElemConsumer* elemConsumer, bool singleValue = false)
427{
428    skipSpacesToLineEnd(ptr, end);
429    if (ptr == end)
430        return;
431   
432    if (*ptr == '[')
433    {
434        ptr++;
435        skipSpacesAndComments(ptr, end, lineNo);
436        while (ptr != end)
437        {
438            // parse in line
439            elemConsumer->consume(ptr, end, lineNo, 0, false, false);
440            skipSpacesAndComments(ptr, end, lineNo);
441            if (ptr!=end && *ptr==']')
442                // just end
443                break;
444            else if (ptr==end || *ptr!=',')
445                throw ParseException(lineNo, "Expected ','");
446            ptr++;
447            skipSpacesAndComments(ptr, end, lineNo);
448        }
449        if (ptr == end)
450            throw ParseException(lineNo, "Unterminated array");
451        ptr++;
452       
453        if (singleValue)
454            skipSpacesToNextLine(ptr, end, lineNo);
455        return;
456    }
457    // sequence
458    size_t oldLineNo = lineNo;
459    size_t indent0 = skipSpacesAndComments(ptr, end, lineNo);
460    if (ptr == end || lineNo == oldLineNo)
461        throw ParseException(lineNo, "Expected sequence of values");
462   
463    if (indent0 < prevIndent)
464        throw ParseException(lineNo, "Unindented sequence of objects");
465   
466    while (ptr != end)
467    {
468        if (*ptr != '-')
469            throw ParseException(lineNo, "No '-' before element value");
470        ptr++;
471        const char* afterMinus = ptr;
472        skipSpacesToLineEnd(ptr, end);
473        if (afterMinus == ptr)
474            throw ParseException(lineNo, "No spaces after '-'");
475        elemConsumer->consume(ptr, end, lineNo, indent0, true, true);
476       
477        size_t indent = skipSpacesAndComments(ptr, end, lineNo);
478        if (indent < indent0)
479        {
480            // if parent level
481            ptr -= indent;
482            break;
483        }
484        if (indent != indent0)
485            throw ParseException(lineNo, "Wrong indentation of element");
486    }
487}
488
489template<typename T>
490class CLRX_INTERNAL YAMLIntArrayConsumer: public YAMLElemConsumer
491{
492private:
493    size_t elemsNum;
494    size_t requiredElemsNum;
495public:
496    T* array;
497   
498    YAMLIntArrayConsumer(size_t reqElemsNum, T* _array)
499            : elemsNum(0), requiredElemsNum(reqElemsNum), array(_array)
500    { }
501   
502    virtual void consume(const char*& ptr, const char* end, size_t& lineNo,
503                cxuint prevIndent, bool singleValue, bool blockAccept)
504    {
505        if (elemsNum == requiredElemsNum)
506            throw ParseException(lineNo, "Too many elements");
507        try
508        { array[elemsNum] = cstrtovCStyle<T>(ptr, end, ptr); }
509        catch(const ParseException& ex)
510        { throw ParseException(lineNo, ex.what()); }
511        elemsNum++;
512        if (singleValue)
513            skipSpacesToNextLine(ptr, end, lineNo);
514    }
515};
516
517// printf info string consumer
518
519class CLRX_INTERNAL YAMLPrintfVectorConsumer: public YAMLElemConsumer
520{
521public:
522    std::vector<ROCmPrintfInfo>& printfInfos;
523   
524    YAMLPrintfVectorConsumer(std::vector<ROCmPrintfInfo>& _printInfos)
525        : printfInfos(_printInfos)
526    { }
527   
528    virtual void consume(const char*& ptr, const char* end, size_t& lineNo,
529                cxuint prevIndent, bool singleValue, bool blockAccept)
530    {
531        const size_t oldLineNo = lineNo;
532        std::string str = parseYAMLStringValue(ptr, end, lineNo, prevIndent,
533                                singleValue, blockAccept);
534        // parse printf string
535        ROCmPrintfInfo printfInfo{};
536       
537        const char* ptr2 = str.c_str();
538        const char* end2 = str.c_str() + str.size();
539        skipSpacesToLineEnd(ptr2, end2);
540        try
541        { printfInfo.id = cstrtovCStyle<uint32_t>(ptr2, end2, ptr2); }
542        catch(const ParseException& ex)
543        { throw ParseException(oldLineNo, ex.what()); }
544        skipSpacesToLineEnd(ptr2, end2);
545        if (ptr2==end || *ptr2!=':')
546            throw ParseException(oldLineNo, "No colon after printf callId");
547        ptr2++;
548        skipSpacesToLineEnd(ptr2, end2);
549        uint32_t argsNum = cstrtovCStyle<uint32_t>(ptr2, end2, ptr2);
550        skipSpacesToLineEnd(ptr2, end2);
551        if (ptr2==end || *ptr2!=':')
552            throw ParseException(oldLineNo, "No colon after printf argsNum");
553        ptr2++;
554       
555        printfInfo.argSizes.resize(argsNum);
556       
557        // parse arg sizes
558        for (size_t i = 0; i < argsNum; i++)
559        {
560            skipSpacesToLineEnd(ptr2, end2);
561            printfInfo.argSizes[i] = cstrtovCStyle<uint32_t>(ptr2, end2, ptr2);
562            skipSpacesToLineEnd(ptr2, end2);
563            if (ptr2==end || *ptr2!=':')
564                throw ParseException(lineNo, "No colon after printf argsNum");
565            ptr2++;
566        }
567        // format
568        printfInfo.format.assign(ptr2, end2);
569       
570        printfInfos.push_back(printfInfo);
571    }
572};
573
574static void skipYAMLValue(const char*& ptr, const char* end, size_t& lineNo,
575                cxuint prevIndent, bool singleValue = true)
576{
577    skipSpacesToLineEnd(ptr, end);
578    if (ptr==end || (*ptr!='\'' && *ptr!='"' && *ptr!='|' && *ptr!='>' && *ptr !='[' &&
579                *ptr!='#' && *ptr!='\n'))
580    {
581        while (ptr!=end && *ptr!='\n') ptr++;
582        skipSpacesToNextLine(ptr, end, lineNo);
583        return;
584    }
585    // string
586    if (*ptr=='\'' || *ptr=='"')
587    {
588        const char delim = *ptr++;
589        bool escape = false;
590        while(ptr!=end && (escape || *ptr!=delim))
591        {
592            if (!escape && *ptr=='\\')
593                escape = true;
594            else if (escape)
595                escape = false;
596            if (*ptr=='\n') lineNo++;
597            ptr++;
598        }
599        if (ptr==end)
600            throw ParseException(lineNo, "Unterminated string");
601        ptr++;
602        if (singleValue)
603            skipSpacesToNextLine(ptr, end, lineNo);
604    }
605    else if (*ptr=='[')
606    {   // otherwise [array]
607        ptr++;
608        skipSpacesAndComments(ptr, end, lineNo);
609        while (ptr != end)
610        {
611            // parse in line
612            if (ptr!=end && (*ptr=='\'' || *ptr=='"'))
613                skipYAMLValue(ptr, end, lineNo, 0, false);
614            else
615                while (ptr!=end && *ptr!='\n' &&
616                            *ptr!='#' && *ptr!=',' && *ptr!=']') ptr++;
617            skipSpacesAndComments(ptr, end, lineNo);
618           
619            if (ptr!=end && *ptr==']')
620                // just end
621                break;
622            else if (ptr!=end && *ptr!=',')
623                throw ParseException(lineNo, "Expected ','");
624            ptr++;
625            skipSpacesAndComments(ptr, end, lineNo);
626        }
627        if (ptr == end)
628            throw ParseException(lineNo, "Unterminated array");
629        ptr++;
630        skipSpacesToNextLine(ptr, end, lineNo);
631    }
632    else
633    {   // block value
634        if (ptr!=end && (*ptr=='|' || *ptr=='>'))
635            ptr++; // skip '|' or '>'
636        if (ptr!=end && *ptr=='#')
637            while (ptr!=end && *ptr!='\n') ptr++;
638        else
639            skipSpacesToLineEnd(ptr, end);
640        if (ptr!=end && *ptr!='\n')
641            throw ParseException(lineNo, "Garbages before block or children");
642        ptr++;
643        lineNo++;
644        // skip all lines indented beyound previous level
645        while (ptr != end)
646        {
647            const char* lineStart = ptr;
648            skipSpacesToLineEnd(ptr, end);
649            if (ptr == end)
650            {
651                ptr++;
652                lineNo++;
653                continue;
654            }
655            if (ptr-lineStart <= prevIndent)
656            {
657                ptr = lineStart;
658                break;
659            }
660           
661            while (ptr!=end && *ptr!='\n') ptr++;
662            if (ptr!=end)
663            {
664                lineNo++;
665                ptr++;
666            }
667        }
668    }
669}
670
671enum {
672    ROCMMT_MAIN_KERNELS = 0, ROCMMT_MAIN_PRINTF,  ROCMMT_MAIN_VERSION
673};
674
675static const char* mainMetadataKeywords[] =
676{
677    "Kernels", "Printf", "Version"
678};
679
680static const size_t mainMetadataKeywordsNum =
681        sizeof(mainMetadataKeywords) / sizeof(const char*);
682
683enum {
684    ROCMMT_KERNEL_ARGS = 0, ROCMMT_KERNEL_ATTRS, ROCMMT_KERNEL_CODEPROPS,
685    ROCMMT_KERNEL_LANGUAGE, ROCMMT_KERNEL_LANGUAGE_VERSION,
686    ROCMMT_KERNEL_NAME, ROCMMT_KERNEL_SYMBOLNAME
687};
688
689static const char* kernelMetadataKeywords[] =
690{
691    "Args", "Attrs", "CodeProps", "Language", "LanguageVersion", "Name", "SymbolName"
692};
693
694static const size_t kernelMetadataKeywordsNum =
695        sizeof(kernelMetadataKeywords) / sizeof(const char*);
696
697enum {
698    ROCMMT_ATTRS_REQD_WORK_GROUP_SIZE = 0, ROCMMT_ATTRS_RUNTIME_HANDLE,
699    ROCMMT_ATTRS_VECTYPEHINT, ROCMMT_ATTRS_WORK_GROUP_SIZE_HINT
700};
701
702static const char* kernelAttrMetadataKeywords[] =
703{
704    "ReqdWorkGroupSize", "RuntimeHandle", "VecTypeHint", "WorkGroupSizeHint"
705};
706
707static const size_t kernelAttrMetadataKeywordsNum =
708        sizeof(kernelAttrMetadataKeywords) / sizeof(const char*);
709
710enum {
711    ROCMMT_CODEPROPS_FIXED_WORK_GROUP_SIZE = 0, ROCMMT_CODEPROPS_GROUP_SEGMENT_FIXED_SIZE,
712    ROCMMT_CODEPROPS_KERNARG_SEGMENT_ALIGN, ROCMMT_CODEPROPS_KERNARG_SEGMENT_SIZE,
713    ROCMMT_CODEPROPS_MAX_FLAT_WORK_GROUP_SIZE, ROCMMT_CODEPROPS_NUM_SGPRS,
714    ROCMMT_CODEPROPS_NUM_SPILLED_SGPRS, ROCMMT_CODEPROPS_NUM_SPILLED_VGPRS,
715    ROCMMT_CODEPROPS_NUM_VGPRS, ROCMMT_CODEPROPS_PRIVATE_SEGMENT_FIXED_SIZE,
716    ROCMMT_CODEPROPS_WAVEFRONT_SIZE
717};
718
719static const char* kernelCodePropsKeywords[] =
720{
721    "FixedWorkGroupSize", "GroupSegmentFixedSize", "KernargSegmentAlign",
722    "KernargSegmentSize", "MaxFlatWorkGroupSize", "NumSGPRs",
723    "NumSpilledSGPRs", "NumSpilledVGPRs", "NumVGPRs", "PrivateSegmentFixedSize",
724    "WavefrontSize"
725};
726
727static const size_t kernelCodePropsKeywordsNum =
728        sizeof(kernelCodePropsKeywords) / sizeof(const char*);
729
730enum {
731    ROCMMT_ARGS_ACCQUAL = 0, ROCMMT_ARGS_ACTUALACCQUAL, ROCMMT_ARGS_ADDRSPACEQUAL,
732    ROCMMT_ARGS_ALIGN, ROCMMT_ARGS_ISCONST, ROCMMT_ARGS_ISPIPE, ROCMMT_ARGS_ISRESTRICT,
733    ROCMMT_ARGS_ISVOLATILE, ROCMMT_ARGS_NAME, ROCMMT_ARGS_POINTEE_ALIGN,
734    ROCMMT_ARGS_SIZE, ROCMMT_ARGS_TYPENAME, ROCMMT_ARGS_VALUEKIND,
735    ROCMMT_ARGS_VALUETYPE
736};
737
738static const char* kernelArgInfosKeywords[] =
739{
740    "AccQual", "ActualAccQual", "AddrSpaceQual", "Align", "IsConst", "IsPipe",
741    "IsRestrict", "IsVolatile", "Name", "PointeeAlign", "Size", "TypeName",
742    "ValueKind", "ValueType"
743};
744
745static const size_t kernelArgInfosKeywordsNum =
746        sizeof(kernelArgInfosKeywords) / sizeof(const char*);
747
748static const std::pair<const char*, ROCmValueKind> rocmValueKindNames[] =
749{
750    { "ByValue", ROCmValueKind::BY_VALUE },
751    { "DynamicSharedPointer", ROCmValueKind::DYN_SHARED_PTR },
752    { "GlobalBuffer", ROCmValueKind::GLOBAL_BUFFER },
753    { "HiddenCompletionAction", ROCmValueKind::HIDDEN_COMPLETION_ACTION },
754    { "HiddenDefaultQueue", ROCmValueKind::HIDDEN_DEFAULT_QUEUE },
755    { "HiddenGlobalOffsetX", ROCmValueKind::HIDDEN_GLOBAL_OFFSET_X },
756    { "HiddenGlobalOffsetY", ROCmValueKind::HIDDEN_GLOBAL_OFFSET_Y },
757    { "HiddenGlobalOffsetZ", ROCmValueKind::HIDDEN_GLOBAL_OFFSET_Z },
758    { "HiddenNone", ROCmValueKind::HIDDEN_NONE },
759    { "HiddenPrintfBuffer", ROCmValueKind::HIDDEN_PRINTF_BUFFER },
760    { "Image", ROCmValueKind::IMAGE },
761    { "Pipe", ROCmValueKind::PIPE },
762    { "Queue", ROCmValueKind::QUEUE },
763    { "Sampler", ROCmValueKind::SAMPLER }
764};
765
766static const size_t rocmValueKindNamesNum =
767        sizeof(rocmValueKindNames) / sizeof(std::pair<const char*, ROCmValueKind>);
768
769static const std::pair<const char*, ROCmValueType> rocmValueTypeNames[] =
770{
771    { "F16", ROCmValueType::FLOAT16 },
772    { "F32", ROCmValueType::FLOAT32 },
773    { "F64", ROCmValueType::FLOAT64 },
774    { "I16", ROCmValueType::INT16 },
775    { "I32", ROCmValueType::INT32 },
776    { "I64", ROCmValueType::INT64 },
777    { "I8", ROCmValueType::INT8 },
778    { "Struct", ROCmValueType::STRUCTURE },
779    { "U16", ROCmValueType::UINT16 },
780    { "U32", ROCmValueType::UINT32 },
781    { "U64", ROCmValueType::UINT64 },
782    { "U8", ROCmValueType::UINT8 }
783};
784
785static const size_t rocmValueTypeNamesNum =
786        sizeof(rocmValueTypeNames) / sizeof(std::pair<const char*, ROCmValueType>);
787
788static const char* rocmAddrSpaceTypesTbl[] =
789{ "Private", "Global", "Constant", "Local", "Generic", "Region" };
790
791static const char* rocmAccessQualifierTbl[] =
792{ "Default", "ReadOnly", "WriteOnly", "ReadWrite" };
793
794static void parseROCmMetadata(size_t metadataSize, const char* metadata,
795                ROCmMetadata& metadataInfo)
796{
797    const char* ptr = metadata;
798    const char* end = metadata + metadataSize;
799    size_t lineNo = 1;
800    // init metadata info object
801    metadataInfo.kernels.clear();
802    metadataInfo.printfInfos.clear();
803    metadataInfo.version[0] = metadataInfo.version[1] = 0;
804   
805    std::vector<ROCmKernelMetadata>& kernels = metadataInfo.kernels;
806   
807    cxuint levels[6] = { UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX };
808    cxuint curLevel = 0;
809    bool inKernels = false;
810    bool inKernel = false;
811    bool inKernelArgs = false;
812    bool inKernelArg = false;
813    bool inKernelCodeProps = false;
814    bool inKernelAttrs = false;
815    bool canToNextLevel = false;
816   
817    size_t oldLineNo = 0;
818    while (ptr != end)
819    {
820        cxuint level = skipSpacesAndComments(ptr, end, lineNo);
821        if (ptr == end || lineNo == oldLineNo)
822            throw ParseException(lineNo, "Expected new line");
823       
824        if (levels[curLevel] == UINT_MAX)
825            levels[curLevel] = level;
826        else if (levels[curLevel] < level)
827        {
828            if (canToNextLevel)
829                // go to next nesting level
830                levels[++curLevel] = level;
831            else
832                throw ParseException(lineNo, "Unexpected nesting level");
833            canToNextLevel = false;
834        }
835        else if (levels[curLevel] > level)
836        {
837            while (curLevel != UINT_MAX && levels[curLevel] > level)
838                curLevel--;
839            if (curLevel == UINT_MAX)
840                throw ParseException(lineNo, "Indentation smaller than in main level");
841           
842            // pop from previous level
843            if (curLevel < 3)
844            {
845                if (inKernelArgs)
846                {
847                    // leave from kernel args
848                    inKernelArgs = false;
849                    inKernelArg = false;
850                }
851           
852                inKernelCodeProps = false;
853                inKernelAttrs = false;
854            }
855            if (curLevel < 1 && inKernels)
856            {
857                // leave from kernels
858                inKernels = false;
859                inKernel = false;
860            }
861           
862            if (levels[curLevel] != level)
863                throw ParseException(lineNo, "Unexpected nesting level");
864        }
865       
866        oldLineNo = lineNo;
867        if (curLevel == 0)
868        {
869            if (lineNo==1 && ptr+3 <= end && *ptr=='-' && ptr[1]=='-' && ptr[2]=='-' &&
870                (ptr+3==end || (ptr+3 < end && ptr[3]=='\n')))
871            {
872                ptr += 3;
873                if (ptr!=end)
874                {
875                    lineNo++;
876                    ptr++; // to newline
877                }
878                continue; // skip document start
879            }
880           
881            if (ptr+3 <= end && *ptr=='.' && ptr[1]=='.' && ptr[2]=='.' &&
882                (ptr+3==end || (ptr+3 < end && ptr[3]=='\n')))
883                break; // end of the document
884           
885            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
886                        mainMetadataKeywordsNum, mainMetadataKeywords);
887           
888            switch(keyIndex)
889            {
890                case ROCMMT_MAIN_KERNELS:
891                    inKernels = true;
892                    canToNextLevel = true;
893                    break;
894                case ROCMMT_MAIN_PRINTF:
895                {
896                    YAMLPrintfVectorConsumer consumer(metadataInfo.printfInfos);
897                    parseYAMLValArray(ptr, end, lineNo, levels[curLevel], &consumer, true);
898                    break;
899                }
900                case ROCMMT_MAIN_VERSION:
901                {
902                    YAMLIntArrayConsumer<uint32_t> consumer(2, metadataInfo.version);
903                    parseYAMLValArray(ptr, end, lineNo, levels[curLevel], &consumer, true);
904                    break;
905                }
906                default:
907                    skipYAMLValue(ptr, end, lineNo, level);
908                    break;
909            }
910        }
911       
912        if (curLevel==1 && inKernels)
913        {
914            // enter to kernel level
915            if (ptr == end || *ptr != '-')
916                throw ParseException(lineNo, "No '-' before kernel object");
917            ptr++;
918            const char* afterMinus = ptr;
919            skipSpacesToLineEnd(ptr, end);
920            levels[++curLevel] = level + 1 + ptr-afterMinus;
921            level = levels[curLevel];
922            inKernel = true;
923           
924            kernels.push_back(ROCmKernelMetadata());
925        }
926       
927        if (curLevel==2 && inKernel)
928        {
929            // in kernel
930            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
931                        kernelMetadataKeywordsNum, kernelMetadataKeywords);
932           
933            ROCmKernelMetadata& kernel = kernels.back();
934            switch(keyIndex)
935            {
936                case ROCMMT_KERNEL_ARGS:
937                    inKernelArgs = true;
938                    canToNextLevel = true;
939                    kernel.argInfos.clear();
940                    break;
941                case ROCMMT_KERNEL_ATTRS:
942                    inKernelAttrs = true;
943                    canToNextLevel = true;
944                    kernel.reqdWorkGroupSize[0] = BINGEN_NOTSUPPLIED;
945                    kernel.reqdWorkGroupSize[1] = BINGEN_NOTSUPPLIED;
946                    kernel.reqdWorkGroupSize[2] = BINGEN_NOTSUPPLIED;
947                    kernel.workGroupSizeHint[0] = BINGEN_NOTSUPPLIED;
948                    kernel.workGroupSizeHint[1] = BINGEN_NOTSUPPLIED;
949                    kernel.workGroupSizeHint[2] = BINGEN_NOTSUPPLIED;
950                    kernel.runtimeHandle.clear();
951                    kernel.vecTypeHint.clear();
952                    break;
953                case ROCMMT_KERNEL_CODEPROPS:
954                    kernel.kernargSegmentSize = BINGEN64_DEFAULT;
955                    kernel.groupSegmentFixedSize = BINGEN64_DEFAULT;
956                    kernel.privateSegmentFixedSize = BINGEN64_DEFAULT;
957                    kernel.kernargSegmentAlign = BINGEN64_DEFAULT;
958                    kernel.wavefrontSize = BINGEN_DEFAULT;
959                    kernel.sgprsNum = BINGEN_DEFAULT;
960                    kernel.vgprsNum = BINGEN_DEFAULT;
961                    kernel.spilledSgprs = BINGEN_NOTSUPPLIED;
962                    kernel.spilledVgprs = BINGEN_NOTSUPPLIED;
963                    kernel.maxFlatWorkGroupSize = BINGEN64_DEFAULT;
964                    kernel.fixedWorkGroupSize[0] = BINGEN_NOTSUPPLIED;
965                    kernel.fixedWorkGroupSize[1] = BINGEN_NOTSUPPLIED;
966                    kernel.fixedWorkGroupSize[2] = BINGEN_NOTSUPPLIED;
967                    inKernelCodeProps = true;
968                    canToNextLevel = true;
969                    break;
970                case ROCMMT_KERNEL_LANGUAGE:
971                    kernel.language = parseYAMLStringValue(ptr, end, lineNo, level, true);
972                    break;
973                case ROCMMT_KERNEL_LANGUAGE_VERSION:
974                {
975                    YAMLIntArrayConsumer<uint32_t> consumer(2, kernel.langVersion);
976                    parseYAMLValArray(ptr, end, lineNo, levels[curLevel], &consumer);
977                    break;
978                }
979                case ROCMMT_KERNEL_NAME:
980                    kernel.name = parseYAMLStringValue(ptr, end, lineNo, level, true);
981                    break;
982                case ROCMMT_KERNEL_SYMBOLNAME:
983                    kernel.symbolName = parseYAMLStringValue(ptr, end, lineNo, level, true);
984                    break;
985                default:
986                    skipYAMLValue(ptr, end, lineNo, level);
987                    break;
988            }
989        }
990       
991        if (curLevel==3 && inKernelAttrs)
992        {
993            // in kernel attributes
994            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
995                        kernelAttrMetadataKeywordsNum, kernelAttrMetadataKeywords);
996           
997            ROCmKernelMetadata& kernel = kernels.back();
998            switch(keyIndex)
999            {
1000                case ROCMMT_ATTRS_REQD_WORK_GROUP_SIZE:
1001                {
1002                    YAMLIntArrayConsumer<cxuint> consumer(3, kernel.reqdWorkGroupSize);
1003                    parseYAMLValArray(ptr, end, lineNo, level, &consumer);
1004                    break;
1005                }
1006                case ROCMMT_ATTRS_RUNTIME_HANDLE:
1007                    kernel.runtimeHandle = parseYAMLStringValue(
1008                                ptr, end, lineNo, level, true);
1009                    break;
1010                case ROCMMT_ATTRS_VECTYPEHINT:
1011                    kernel.vecTypeHint = parseYAMLStringValue(
1012                                ptr, end, lineNo, level, true);
1013                    break;
1014                case ROCMMT_ATTRS_WORK_GROUP_SIZE_HINT:
1015                {
1016                    YAMLIntArrayConsumer<cxuint> consumer(3, kernel.workGroupSizeHint);
1017                    parseYAMLValArray(ptr, end, lineNo, level, &consumer, true);
1018                    break;
1019                }
1020                default:
1021                    skipYAMLValue(ptr, end, lineNo, level);
1022                    break;
1023            }
1024        }
1025       
1026        if (curLevel==3 && inKernelCodeProps)
1027        {
1028            // in kernel codeProps
1029            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1030                        kernelCodePropsKeywordsNum, kernelCodePropsKeywords);
1031           
1032            ROCmKernelMetadata& kernel = kernels.back();
1033            switch(keyIndex)
1034            {
1035                case ROCMMT_CODEPROPS_FIXED_WORK_GROUP_SIZE:
1036                {
1037                    YAMLIntArrayConsumer<cxuint> consumer(3, kernel.fixedWorkGroupSize);
1038                    parseYAMLValArray(ptr, end, lineNo, level, &consumer);
1039                    break;
1040                }
1041                case ROCMMT_CODEPROPS_GROUP_SEGMENT_FIXED_SIZE:
1042                    kernel.groupSegmentFixedSize =
1043                                parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1044                    break;
1045                case ROCMMT_CODEPROPS_KERNARG_SEGMENT_ALIGN:
1046                    kernel.kernargSegmentAlign =
1047                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1048                    break;
1049                case ROCMMT_CODEPROPS_KERNARG_SEGMENT_SIZE:
1050                    kernel.kernargSegmentSize =
1051                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1052                    break;
1053                case ROCMMT_CODEPROPS_MAX_FLAT_WORK_GROUP_SIZE:
1054                    kernel.maxFlatWorkGroupSize =
1055                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1056                    break;
1057                case ROCMMT_CODEPROPS_NUM_SGPRS:
1058                    kernel.sgprsNum = parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1059                    break;
1060                case ROCMMT_CODEPROPS_NUM_SPILLED_SGPRS:
1061                    kernel.spilledSgprs =
1062                            parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1063                    break;
1064                case ROCMMT_CODEPROPS_NUM_SPILLED_VGPRS:
1065                    kernel.spilledVgprs =
1066                            parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1067                    break;
1068                case ROCMMT_CODEPROPS_NUM_VGPRS:
1069                    kernel.vgprsNum = parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1070                    break;
1071                case ROCMMT_CODEPROPS_PRIVATE_SEGMENT_FIXED_SIZE:
1072                    kernel.privateSegmentFixedSize =
1073                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1074                    break;
1075                case ROCMMT_CODEPROPS_WAVEFRONT_SIZE:
1076                    kernel.wavefrontSize =
1077                            parseYAMLIntValue<cxuint>(ptr, end, lineNo, true);
1078                    break;
1079                default:
1080                    skipYAMLValue(ptr, end, lineNo, level);
1081                    break;
1082            }
1083        }
1084       
1085        if (curLevel==3 && inKernelArgs)
1086        {
1087            // enter to kernel argument level
1088            if (ptr == end || *ptr != '-')
1089                throw ParseException(lineNo, "No '-' before argument object");
1090            ptr++;
1091            const char* afterMinus = ptr;
1092            skipSpacesToLineEnd(ptr, end);
1093            levels[++curLevel] = level + 1 + ptr-afterMinus;
1094            level = levels[curLevel];
1095            inKernelArg = true;
1096           
1097            kernels.back().argInfos.push_back(ROCmKernelArgInfo{});
1098        }
1099       
1100        if (curLevel==4 && inKernelArg)
1101        {
1102            // in kernel argument
1103            const size_t keyIndex = parseYAMLKey(ptr, end, lineNo,
1104                        kernelArgInfosKeywordsNum, kernelArgInfosKeywords);
1105           
1106            ROCmKernelArgInfo& kernelArg = kernels.back().argInfos.back();
1107           
1108            size_t valLineNo = lineNo;
1109            switch(keyIndex)
1110            {
1111                case ROCMMT_ARGS_ACCQUAL:
1112                case ROCMMT_ARGS_ACTUALACCQUAL:
1113                {
1114                    const std::string acc = trimStrSpaces(parseYAMLStringValue(
1115                                    ptr, end, lineNo, level, true));
1116                    size_t accIndex = 0;
1117                    for (; accIndex < 6; accIndex++)
1118                        if (::strcmp(rocmAccessQualifierTbl[accIndex], acc.c_str())==0)
1119                            break;
1120                    if (accIndex == 4)
1121                        throw ParseException(lineNo, "Wrong access qualifier");
1122                    if (keyIndex == ROCMMT_ARGS_ACCQUAL)
1123                        kernelArg.accessQual = ROCmAccessQual(accIndex);
1124                    else
1125                        kernelArg.actualAccessQual = ROCmAccessQual(accIndex);
1126                    break;
1127                }
1128                case ROCMMT_ARGS_ADDRSPACEQUAL:
1129                {
1130                    const std::string aspace = trimStrSpaces(parseYAMLStringValue(
1131                                    ptr, end, lineNo, level, true));
1132                    size_t aspaceIndex = 0;
1133                    for (; aspaceIndex < 6; aspaceIndex++)
1134                        if (::strcmp(rocmAddrSpaceTypesTbl[aspaceIndex],
1135                                    aspace.c_str())==0)
1136                            break;
1137                    if (aspaceIndex == 6)
1138                        throw ParseException(valLineNo, "Wrong address space");
1139                    kernelArg.addressSpace = ROCmAddressSpace(aspaceIndex+1);
1140                    break;
1141                }
1142                case ROCMMT_ARGS_ALIGN:
1143                    kernelArg.align = parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1144                    break;
1145                case ROCMMT_ARGS_ISCONST:
1146                    kernelArg.isConst = parseYAMLBoolValue(ptr, end, lineNo, true);
1147                    break;
1148                case ROCMMT_ARGS_ISPIPE:
1149                    kernelArg.isPipe = parseYAMLBoolValue(ptr, end, lineNo, true);
1150                    break;
1151                case ROCMMT_ARGS_ISRESTRICT:
1152                    kernelArg.isRestrict = parseYAMLBoolValue(ptr, end, lineNo, true);
1153                    break;
1154                case ROCMMT_ARGS_ISVOLATILE:
1155                    kernelArg.isVolatile = parseYAMLBoolValue(ptr, end, lineNo, true);
1156                    break;
1157                case ROCMMT_ARGS_NAME:
1158                    kernelArg.name = parseYAMLStringValue(ptr, end, lineNo, level, true);
1159                    break;
1160                case ROCMMT_ARGS_POINTEE_ALIGN:
1161                    kernelArg.pointeeAlign =
1162                                parseYAMLIntValue<uint64_t>(ptr, end, lineNo, true);
1163                    break;
1164                case ROCMMT_ARGS_SIZE:
1165                    kernelArg.size = parseYAMLIntValue<uint64_t>(ptr, end, lineNo);
1166                    break;
1167                case ROCMMT_ARGS_TYPENAME:
1168                    kernelArg.typeName =
1169                                parseYAMLStringValue(ptr, end, lineNo, level, true);
1170                    break;
1171                case ROCMMT_ARGS_VALUEKIND:
1172                {
1173                    const std::string vkind = trimStrSpaces(parseYAMLStringValue(
1174                                ptr, end, lineNo, level, true));
1175                    const size_t vkindIndex = binaryMapFind(rocmValueKindNames,
1176                            rocmValueKindNames + rocmValueKindNamesNum, vkind.c_str(),
1177                            CStringLess()) - rocmValueKindNames;
1178                    // if unknown kind
1179                    if (vkindIndex == rocmValueKindNamesNum)
1180                        throw ParseException(valLineNo, "Wrong argument value kind");
1181                    kernelArg.valueKind = rocmValueKindNames[vkindIndex].second;
1182                    break;
1183                }
1184                case ROCMMT_ARGS_VALUETYPE:
1185                {
1186                    const std::string vtype = trimStrSpaces(parseYAMLStringValue(
1187                                    ptr, end, lineNo, level, true));
1188                    const size_t vtypeIndex = binaryMapFind(rocmValueTypeNames,
1189                            rocmValueTypeNames + rocmValueTypeNamesNum, vtype.c_str(),
1190                            CStringLess()) - rocmValueTypeNames;
1191                    // if unknown type
1192                    if (vtypeIndex == rocmValueTypeNamesNum)
1193                        throw ParseException(valLineNo, "Wrong argument value type");
1194                    kernelArg.valueType = rocmValueTypeNames[vtypeIndex].second;
1195                    break;
1196                }
1197                default:
1198                    skipYAMLValue(ptr, end, lineNo, level);
1199                    break;
1200            }
1201        }
1202    }
1203}
1204
1205/*
1206 * ROCm binary reader and generator
1207 */
1208
1209/* TODO: add support for various kernel code offset (now only 256 is supported) */
1210
1211ROCmBinary::ROCmBinary(size_t binaryCodeSize, cxbyte* binaryCode, Flags creationFlags)
1212        : ElfBinary64(binaryCodeSize, binaryCode, creationFlags),
1213          regionsNum(0), codeSize(0), code(nullptr),
1214          globalDataSize(0), globalData(nullptr), metadataSize(0), metadata(nullptr),
1215          newBinFormat(false)
1216{
1217    cxuint textIndex = SHN_UNDEF;
1218    try
1219    { textIndex = getSectionIndex(".text"); }
1220    catch(const Exception& ex)
1221    { } // ignore failed
1222    uint64_t codeOffset = 0;
1223    // find '.text' section
1224    if (textIndex!=SHN_UNDEF)
1225    {
1226        code = getSectionContent(textIndex);
1227        const Elf64_Shdr& textShdr = getSectionHeader(textIndex);
1228        codeSize = ULEV(textShdr.sh_size);
1229        codeOffset = ULEV(textShdr.sh_offset);
1230    }
1231   
1232    cxuint rodataIndex = SHN_UNDEF;
1233    try
1234    { rodataIndex = getSectionIndex(".rodata"); }
1235    catch(const Exception& ex)
1236    { } // ignore failed
1237    // find '.text' section
1238    if (rodataIndex!=SHN_UNDEF)
1239    {
1240        globalData = getSectionContent(rodataIndex);
1241        const Elf64_Shdr& rodataShdr = getSectionHeader(rodataIndex);
1242        globalDataSize = ULEV(rodataShdr.sh_size);
1243    }
1244   
1245    cxuint gpuConfigIndex = SHN_UNDEF;
1246    try
1247    { gpuConfigIndex = getSectionIndex(".AMDGPU.config"); }
1248    catch(const Exception& ex)
1249    { } // ignore failed
1250    newBinFormat = (gpuConfigIndex == SHN_UNDEF);
1251   
1252    // counts regions (symbol or kernel)
1253    regionsNum = 0;
1254    const size_t symbolsNum = getSymbolsNum();
1255    for (size_t i = 0; i < symbolsNum; i++)
1256    {
1257        // count regions number
1258        const Elf64_Sym& sym = getSymbol(i);
1259        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
1260        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
1261        if (ULEV(sym.st_shndx)==textIndex &&
1262            (symType==STT_GNU_IFUNC || symType==STT_FUNC ||
1263                (bind==STB_GLOBAL && symType==STT_OBJECT)))
1264            regionsNum++;
1265    }
1266    if (code==nullptr && regionsNum!=0)
1267        throw BinException("No code if regions number is not zero");
1268    regions.reset(new ROCmRegion[regionsNum]);
1269    size_t j = 0;
1270    typedef std::pair<uint64_t, size_t> RegionOffsetEntry;
1271    std::unique_ptr<RegionOffsetEntry[]> symOffsets(new RegionOffsetEntry[regionsNum]);
1272   
1273    // get regions info
1274    for (size_t i = 0; i < symbolsNum; i++)
1275    {
1276        const Elf64_Sym& sym = getSymbol(i);
1277        if (ULEV(sym.st_shndx)!=textIndex)
1278            continue;   // if not in '.text' section
1279        const size_t value = ULEV(sym.st_value);
1280        if (value < codeOffset)
1281            throw BinException("Region offset is too small!");
1282        const size_t size = ULEV(sym.st_size);
1283       
1284        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
1285        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
1286        if (symType==STT_GNU_IFUNC || symType==STT_FUNC ||
1287                (bind==STB_GLOBAL && symType==STT_OBJECT))
1288        {
1289            ROCmRegionType type = ROCmRegionType::DATA;
1290            // if kernel
1291            if (symType==STT_GNU_IFUNC) 
1292                type = ROCmRegionType::KERNEL;
1293            // if function kernel
1294            else if (symType==STT_FUNC)
1295                type = ROCmRegionType::FKERNEL;
1296            symOffsets[j] = std::make_pair(value, j);
1297            if (type!=ROCmRegionType::DATA && value+0x100 > codeOffset+codeSize)
1298                throw BinException("Kernel or code offset is too big!");
1299            regions[j++] = { getSymbolName(i), size, value, type };
1300        }
1301    }
1302    // sort regions by offset
1303    std::sort(symOffsets.get(), symOffsets.get()+regionsNum,
1304            [](const RegionOffsetEntry& a, const RegionOffsetEntry& b)
1305            { return a.first < b.first; });
1306    // checking distance between regions
1307    for (size_t i = 1; i <= regionsNum; i++)
1308    {
1309        size_t end = (i<regionsNum) ? symOffsets[i].first : codeOffset+codeSize;
1310        ROCmRegion& region = regions[symOffsets[i-1].second];
1311        if (region.type==ROCmRegionType::KERNEL && symOffsets[i-1].first+0x100 > end)
1312            throw BinException("Kernel size is too small!");
1313       
1314        const size_t regSize = end - symOffsets[i-1].first;
1315        if (region.size==0)
1316            region.size = regSize;
1317        else
1318            region.size = std::min(regSize, region.size);
1319    }
1320   
1321    // get metadata
1322    const size_t notesSize = getNotesSize();
1323    const cxbyte* noteContent = (const cxbyte*)getNotes();
1324   
1325    for (size_t offset = 0; offset < notesSize; )
1326    {
1327        const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
1328        size_t namesz = ULEV(nhdr->n_namesz);
1329        size_t descsz = ULEV(nhdr->n_descsz);
1330        if (usumGt(offset, namesz+descsz, notesSize))
1331            throw BinException("Note offset+size out of range");
1332       
1333        if (namesz==4 &&
1334            ::strcmp((const char*)noteContent+offset+ sizeof(Elf64_Nhdr), "AMD")==0)
1335        {
1336            const uint32_t noteType = ULEV(nhdr->n_type);
1337            if (noteType == 0xa)
1338            {
1339                metadata = (char*)(noteContent+offset+sizeof(Elf64_Nhdr) + 4);
1340                metadataSize = descsz;
1341            }
1342            else if (noteType == 0xb)
1343                target.assign((char*)(noteContent+offset+sizeof(Elf64_Nhdr) + 4), descsz);
1344        }
1345        size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
1346        offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
1347    }
1348   
1349    if (hasRegionMap())
1350    {
1351        // create region map
1352        regionsMap.resize(regionsNum);
1353        for (size_t i = 0; i < regionsNum; i++)
1354            regionsMap[i] = std::make_pair(regions[i].regionName, i);
1355        // sort region map
1356        mapSort(regionsMap.begin(), regionsMap.end());
1357    }
1358   
1359    if ((creationFlags & ROCMBIN_CREATE_METADATAINFO) != 0 &&
1360        metadata != nullptr && metadataSize != 0)
1361    {
1362        metadataInfo.reset(new ROCmMetadata());
1363        parseROCmMetadata(metadataSize, metadata, *metadataInfo);
1364       
1365        if (hasKernelInfoMap())
1366        {
1367            const std::vector<ROCmKernelMetadata>& kernels = metadataInfo->kernels;
1368            kernelInfosMap.resize(kernels.size());
1369            for (size_t i = 0; i < kernelInfosMap.size(); i++)
1370                kernelInfosMap[i] = std::make_pair(kernels[i].name, i);
1371            // sort region map
1372            mapSort(kernelInfosMap.begin(), kernelInfosMap.end());
1373        }
1374    }
1375}
1376
1377/// determint GPU device from ROCm notes
1378GPUDeviceType ROCmBinary::determineGPUDeviceType(uint32_t& outArchMinor,
1379                     uint32_t& outArchStepping) const
1380{
1381    uint32_t archMajor = 0;
1382    uint32_t archMinor = 0;
1383    uint32_t archStepping = 0;
1384   
1385    {
1386        const cxbyte* noteContent = (const cxbyte*)getNotes();
1387        if (noteContent==nullptr)
1388            throw BinException("Missing notes in inner binary!");
1389        size_t notesSize = getNotesSize();
1390        // find note about AMDGPU
1391        for (size_t offset = 0; offset < notesSize; )
1392        {
1393            const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
1394            size_t namesz = ULEV(nhdr->n_namesz);
1395            size_t descsz = ULEV(nhdr->n_descsz);
1396            if (usumGt(offset, namesz+descsz, notesSize))
1397                throw BinException("Note offset+size out of range");
1398            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
1399                ::strcmp((const char*)noteContent+offset+sizeof(Elf64_Nhdr), "AMD")==0)
1400            {    // AMDGPU type
1401                const uint32_t* content = (const uint32_t*)
1402                        (noteContent+offset+sizeof(Elf64_Nhdr) + 4);
1403                archMajor = ULEV(content[1]);
1404                archMinor = ULEV(content[2]);
1405                archStepping = ULEV(content[3]);
1406            }
1407            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
1408            offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
1409        }
1410    }
1411    // determine device type
1412    GPUDeviceType deviceType = getGPUDeviceTypeFromArchVersion(archMajor, archMinor,
1413                                    archStepping);
1414    outArchMinor = archMinor;
1415    outArchStepping = archStepping;
1416    return deviceType;
1417}
1418
1419const ROCmRegion& ROCmBinary::getRegion(const char* name) const
1420{
1421    RegionMap::const_iterator it = binaryMapFind(regionsMap.begin(),
1422                             regionsMap.end(), name);
1423    if (it == regionsMap.end())
1424        throw BinException("Can't find region name");
1425    return regions[it->second];
1426}
1427
1428const ROCmKernelMetadata& ROCmBinary::getKernelInfo(const char* name) const
1429{
1430    if (!hasMetadataInfo())
1431        throw BinException("Can't find kernel info name");
1432    RegionMap::const_iterator it = binaryMapFind(kernelInfosMap.begin(),
1433                             kernelInfosMap.end(), name);
1434    if (it == kernelInfosMap.end())
1435        throw BinException("Can't find kernel info name");
1436    return metadataInfo->kernels[it->second];
1437}
1438
1439// if ROCm binary
1440bool CLRX::isROCmBinary(size_t binarySize, const cxbyte* binary)
1441{
1442    if (!isElfBinary(binarySize, binary))
1443        return false;
1444    if (binary[EI_CLASS] != ELFCLASS64)
1445        return false;
1446    const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr*>(binary);
1447    if (ULEV(ehdr->e_machine) != 0xe0)
1448        return false;
1449    return true;
1450}
1451
1452
1453void ROCmInput::addEmptyKernel(const char* kernelName)
1454{
1455    symbols.push_back({ kernelName, 0, 0, ROCmRegionType::KERNEL });
1456}
1457
1458/*
1459 * ROCm Binary Generator
1460 */
1461
1462ROCmBinGenerator::ROCmBinGenerator() : manageable(false), input(nullptr)
1463{ }
1464
1465ROCmBinGenerator::ROCmBinGenerator(const ROCmInput* rocmInput)
1466        : manageable(false), input(rocmInput)
1467{ }
1468
1469ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
1470        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
1471        size_t globalDataSize, const cxbyte* globalData,
1472        const std::vector<ROCmSymbolInput>& symbols)
1473{
1474    input = new ROCmInput{ deviceType, archMinor, archStepping, 0, false,
1475            globalDataSize, globalData, symbols, codeSize, code };
1476}
1477
1478ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
1479        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
1480        size_t globalDataSize, const cxbyte* globalData,
1481        std::vector<ROCmSymbolInput>&& symbols)
1482{
1483    input = new ROCmInput{ deviceType, archMinor, archStepping, 0, false,
1484            globalDataSize, globalData, std::move(symbols), codeSize, code };
1485}
1486
1487ROCmBinGenerator::~ROCmBinGenerator()
1488{
1489    if (manageable)
1490        delete input;
1491}
1492
1493void ROCmBinGenerator::setInput(const ROCmInput* input)
1494{
1495    if (manageable)
1496        delete input;
1497    manageable = false;
1498    this->input = input;
1499}
1500
1501// ELF notes contents
1502static const cxbyte noteDescType1[8] =
1503{ 2, 0, 0, 0, 1, 0, 0, 0 };
1504
1505static const cxbyte noteDescType3[27] =
1506{ 4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1507  'A', 'M', 'D', 0, 'A', 'M', 'D', 'G', 'P', 'U', 0 };
1508
1509static inline void addMainSectionToTable(cxuint& sectionsNum, uint16_t* builtinTable,
1510                cxuint elfSectId)
1511{ builtinTable[elfSectId - ELFSECTID_START] = sectionsNum++; }
1512
1513void ROCmBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
1514             Array<cxbyte>* aPtr) const
1515{
1516    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(input->deviceType,
1517                GPUArchVersionTable::ROCM);
1518    if (input->archMinor!=UINT32_MAX)
1519        amdGpuArchValues.minor = input->archMinor;
1520    if (input->archStepping!=UINT32_MAX)
1521        amdGpuArchValues.stepping = input->archStepping;
1522   
1523    const char* comment = "CLRX ROCmBinGenerator " CLRX_VERSION;
1524    uint32_t commentSize = ::strlen(comment);
1525    if (input->comment!=nullptr)
1526    {
1527        // if comment, store comment section
1528        comment = input->comment;
1529        commentSize = input->commentSize;
1530        if (commentSize==0)
1531            commentSize = ::strlen(comment);
1532    }
1533   
1534    uint32_t eflags = input->newBinFormat ? 2 : 0;
1535    if (input->eflags != BINGEN_DEFAULT)
1536        eflags = input->eflags;
1537   
1538    ElfBinaryGen64 elfBinGen64({ 0U, 0U, 0x40, 0, ET_DYN,
1539            0xe0, EV_CURRENT, UINT_MAX, 0, eflags },
1540            true, true, true, PHREGION_FILESTART);
1541   
1542    uint16_t mainBuiltinSectTable[ROCMSECTID_MAX-ELFSECTID_START+1];
1543    std::fill(mainBuiltinSectTable,
1544              mainBuiltinSectTable + ROCMSECTID_MAX-ELFSECTID_START+1, SHN_UNDEF);
1545    cxuint mainSectionsNum = 1;
1546   
1547    // generate main builtin section table (for section id translation)
1548    if (input->newBinFormat)
1549        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
1550    if (input->globalData != nullptr)
1551        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_RODATA);
1552    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSYM);
1553    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_HASH);
1554    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSTR);
1555    const cxuint execProgHeaderRegionIndex = mainSectionsNum;
1556    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_TEXT);
1557    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_DYNAMIC);
1558    if (!input->newBinFormat)
1559    {
1560        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
1561        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GPUCONFIG);
1562    }
1563    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_COMMENT);
1564    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SYMTAB);
1565    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SHSTRTAB);
1566    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_STRTAB);
1567   
1568    // add symbols (kernels, function kernels and data symbols)
1569    elfBinGen64.addSymbol(ElfSymbol64("_DYNAMIC",
1570                  mainBuiltinSectTable[ROCMSECTID_DYNAMIC-ELFSECTID_START],
1571                  ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE), STV_HIDDEN, true, 0, 0));
1572    const uint16_t textSectIndex = mainBuiltinSectTable[ELFSECTID_TEXT-ELFSECTID_START];
1573    for (const ROCmSymbolInput& symbol: input->symbols)
1574    {
1575        ElfSymbol64 elfsym;
1576        switch (symbol.type)
1577        {
1578            case ROCmRegionType::KERNEL:
1579                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
1580                      ELF64_ST_INFO(STB_GLOBAL, STT_GNU_IFUNC), 0, true,
1581                      symbol.offset, symbol.size);
1582                break;
1583            case ROCmRegionType::FKERNEL:
1584                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
1585                      ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), 0, true,
1586                      symbol.offset, symbol.size);
1587                break;
1588            case ROCmRegionType::DATA:
1589                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
1590                      ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT), 0, true,
1591                      symbol.offset, symbol.size);
1592                break;
1593            default:
1594                break;
1595        }
1596        // add to symbols and dynamic symbols table
1597        elfBinGen64.addSymbol(elfsym);
1598        elfBinGen64.addDynSymbol(elfsym);
1599    }
1600   
1601    static const int32_t dynTags[] = {
1602        DT_SYMTAB, DT_SYMENT, DT_STRTAB, DT_STRSZ, DT_HASH };
1603    elfBinGen64.addDynamics(sizeof(dynTags)/sizeof(int32_t), dynTags);
1604   
1605    // elf program headers
1606    elfBinGen64.addProgramHeader({ PT_PHDR, PF_R, 0, 1,
1607                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
1608    elfBinGen64.addProgramHeader({ PT_LOAD, PF_R, PHREGION_FILESTART,
1609                    execProgHeaderRegionIndex,
1610                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 0x1000 });
1611    elfBinGen64.addProgramHeader({ PT_LOAD, PF_R|PF_X, execProgHeaderRegionIndex, 1,
1612                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
1613    elfBinGen64.addProgramHeader({ PT_LOAD, PF_R|PF_W, execProgHeaderRegionIndex+1, 1,
1614                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
1615    elfBinGen64.addProgramHeader({ PT_DYNAMIC, PF_R|PF_W, execProgHeaderRegionIndex+1, 1,
1616                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 8 });
1617    elfBinGen64.addProgramHeader({ PT_GNU_RELRO, PF_R, execProgHeaderRegionIndex+1, 1,
1618                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 1 });
1619    elfBinGen64.addProgramHeader({ PT_GNU_STACK, PF_R|PF_W, PHREGION_FILESTART, 0,
1620                    true, 0, 0, 0 });
1621   
1622    if (input->newBinFormat)
1623        // program header for note (new binary format)
1624        elfBinGen64.addProgramHeader({ PT_NOTE, PF_R, 1, 1, true,
1625                    Elf64Types::nobase, Elf64Types::nobase, 0, 4 });
1626   
1627    std::string target = input->target.c_str();
1628    if (target.empty() && !input->targetTripple.empty())
1629    {
1630        target = input->targetTripple.c_str();
1631        char dbuf[20];
1632        snprintf(dbuf, 20, "-gfx%u%u%u", amdGpuArchValues.major, amdGpuArchValues.minor,
1633                 amdGpuArchValues.stepping);
1634        target += dbuf;
1635    }
1636    // elf notes
1637    elfBinGen64.addNote({"AMD", sizeof noteDescType1, noteDescType1, 1U});
1638    std::unique_ptr<cxbyte[]> noteBuf(new cxbyte[0x1b]);
1639    ::memcpy(noteBuf.get(), noteDescType3, 0x1b);
1640    SULEV(*(uint32_t*)(noteBuf.get()+4), amdGpuArchValues.major);
1641    SULEV(*(uint32_t*)(noteBuf.get()+8), amdGpuArchValues.minor);
1642    SULEV(*(uint32_t*)(noteBuf.get()+12), amdGpuArchValues.stepping);
1643    elfBinGen64.addNote({"AMD", 0x1b, noteBuf.get(), 3U});
1644    if (!target.empty())
1645        elfBinGen64.addNote({"AMD", target.size(), (const cxbyte*)target.c_str(), 0xbU});
1646    if (input->metadataSize != 0)
1647        elfBinGen64.addNote({"AMD", input->metadataSize,
1648                (const cxbyte*)input->metadata, 0xaU});
1649   
1650    /// region and sections
1651    elfBinGen64.addRegion(ElfRegion64::programHeaderTable());
1652    if (input->newBinFormat)
1653        elfBinGen64.addRegion(ElfRegion64::noteSection());
1654    if (input->globalData != nullptr)
1655        elfBinGen64.addRegion(ElfRegion64(input->globalDataSize, input->globalData, 4,
1656                ".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, Elf64Types::nobase));
1657   
1658    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
1659                ".dynsym", SHT_DYNSYM, SHF_ALLOC, 0, 1, Elf64Types::nobase));
1660    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 4,
1661                ".hash", SHT_HASH, SHF_ALLOC,
1662                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
1663                Elf64Types::nobase));
1664    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".dynstr", SHT_STRTAB,
1665                SHF_ALLOC, 0, 0, Elf64Types::nobase));
1666    // '.text' with alignment=4096
1667    elfBinGen64.addRegion(ElfRegion64(input->codeSize, (const cxbyte*)input->code, 
1668              0x1000, ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 0, 0,
1669              Elf64Types::nobase, 0, false, 256));
1670    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 0x1000,
1671                ".dynamic", SHT_DYNAMIC, SHF_ALLOC|SHF_WRITE,
1672                mainBuiltinSectTable[ELFSECTID_DYNSTR-ELFSECTID_START], 0,
1673                Elf64Types::nobase, 0, false, 8));
1674    if (!input->newBinFormat)
1675    {
1676        elfBinGen64.addRegion(ElfRegion64::noteSection());
1677        elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1,
1678                    ".AMDGPU.config", SHT_PROGBITS, 0));
1679    }
1680    elfBinGen64.addRegion(ElfRegion64(commentSize, (const cxbyte*)comment, 1, ".comment",
1681              SHT_PROGBITS, SHF_MERGE|SHF_STRINGS, 0, 0, 0, 1));
1682    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
1683                ".symtab", SHT_SYMTAB, 0, 0, 2));
1684    elfBinGen64.addRegion(ElfRegion64::shstrtabSection());
1685    elfBinGen64.addRegion(ElfRegion64::strtabSection());
1686    elfBinGen64.addRegion(ElfRegion64::sectionHeaderTable());
1687   
1688    /* extra sections */
1689    for (const BinSection& section: input->extraSections)
1690        elfBinGen64.addRegion(ElfRegion64(section, mainBuiltinSectTable,
1691                         ROCMSECTID_MAX, mainSectionsNum));
1692    /* extra symbols */
1693    for (const BinSymbol& symbol: input->extraSymbols)
1694        elfBinGen64.addSymbol(ElfSymbol64(symbol, mainBuiltinSectTable,
1695                         ROCMSECTID_MAX, mainSectionsNum));
1696   
1697    size_t binarySize = elfBinGen64.countSize();
1698    /****
1699     * prepare for write binary to output
1700     ****/
1701    std::unique_ptr<std::ostream> outStreamHolder;
1702    std::ostream* os = nullptr;
1703    if (aPtr != nullptr)
1704    {
1705        aPtr->resize(binarySize);
1706        outStreamHolder.reset(
1707                new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
1708        os = outStreamHolder.get();
1709    }
1710    else if (vPtr != nullptr)
1711    {
1712        vPtr->resize(binarySize);
1713        outStreamHolder.reset(new VectorOStream(*vPtr));
1714        os = outStreamHolder.get();
1715    }
1716    else // from argument
1717        os = osPtr;
1718   
1719    const std::ios::iostate oldExceptions = os->exceptions();
1720    try
1721    {
1722    os->exceptions(std::ios::failbit | std::ios::badbit);
1723    /****
1724     * write binary to output
1725     ****/
1726    FastOutputBuffer bos(256, *os);
1727    elfBinGen64.generate(bos);
1728    assert(bos.getWritten() == binarySize);
1729    }
1730    catch(...)
1731    {
1732        os->exceptions(oldExceptions);
1733        throw;
1734    }
1735    os->exceptions(oldExceptions);
1736}
1737
1738void ROCmBinGenerator::generate(Array<cxbyte>& array) const
1739{
1740    generateInternal(nullptr, nullptr, &array);
1741}
1742
1743void ROCmBinGenerator::generate(std::ostream& os) const
1744{
1745    generateInternal(&os, nullptr, nullptr);
1746}
1747
1748void ROCmBinGenerator::generate(std::vector<char>& v) const
1749{
1750    generateInternal(nullptr, &v, nullptr);
1751}
Note: See TracBrowser for help on using the repository browser.