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

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

CLRadeonExtender: ROCmMetadata: Fixed parse error message. Add testcases with error.

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