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

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

CLRadeonExtender: ROCmMetadata: Do not accept block string inside array []. Fixed prevIndent in consume method call.

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