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

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

CLRadeonExtender: ROCmBin: Make constructors for ROCmMetadata and ROCmKernelMetadata. Initialize values for CodeProps? after opening it.
Reorder ROCmAccessQualifier enums.

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