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

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

CLRadeonExtender: ROCmMetadata: Small changes. Commeting code.

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