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

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

CLRadeonExtender: ROCmBinGen: Use hasValue to check whether field has value.

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