source: CLRX/CLRadeonExtender/trunk/amdasm/DisasmAmd.cpp @ 4958

Last change on this file since 4958 was 4958, checked in by matszpk, 13 months ago

CLRadeonExtender: AmdBin?: Fixed old bug in parsing metadata.

File size: 63.3 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 <cstdint>
22#include <cstdio>
23#include <string>
24#include <ostream>
25#include <memory>
26#include <inttypes.h>
27#include <unordered_map>
28#include <cstring>
29#include <vector>
30#include <utility>
31#include <algorithm>
32#include <CLRX/utils/Utilities.h>
33#include <CLRX/utils/Containers.h>
34#include <CLRX/utils/MemAccess.h>
35#include <CLRX/amdbin/AmdBinaries.h>
36#include <CLRX/amdbin/AmdCL2BinGen.h>
37#include <CLRX/amdasm/Disassembler.h>
38#include <CLRX/utils/GPUId.h>
39#include "DisasmInternals.h"
40
41using namespace CLRX;
42
43// get AMD kernel input from inner binary
44static void getAmdDisasmKernelInputFromBinary(const AmdInnerGPUBinary32* innerBin,
45        AmdDisasmKernelInput& kernelInput, Flags flags, GPUDeviceType inputDeviceType)
46{
47    kernelInput.codeSize = kernelInput.dataSize = 0;
48    kernelInput.code = kernelInput.data = nullptr;
49   
50    if (innerBin != nullptr)
51    {
52        // if innerBinary exists
53        bool codeFound = false;
54        bool dataFound = false;
55        cxuint encEntryIndex = innerBin->findCALEncodingEntryIndex(inputDeviceType);
56        const CALEncodingEntry& encEntry = innerBin->getCALEncodingEntry(encEntryIndex);
57        const size_t encEntryOffset = ULEV(encEntry.offset);
58        const size_t encEntrySize = ULEV(encEntry.size);
59        /* find suitable sections */
60        for (cxuint j = 0; j < innerBin->getSectionHeadersNum(); j++)
61        {
62            const char* secName = innerBin->getSectionName(j);
63            const Elf32_Shdr& shdr = innerBin->getSectionHeader(j);
64            const size_t secOffset = ULEV(shdr.sh_offset);
65            const size_t secSize = ULEV(shdr.sh_size);
66            if (secOffset < encEntryOffset ||
67                    usumGt(secOffset, secSize, encEntryOffset+encEntrySize))
68                continue; // skip this section (not in choosen encoding)
69           
70            // set code and data sections (if exists)
71            if (!codeFound && ::strcmp(secName, ".text") == 0)
72            {
73                kernelInput.codeSize = secSize;
74                kernelInput.code = innerBin->getSectionContent(j);
75                codeFound = true;
76            }
77            else if (!dataFound && ::strcmp(secName, ".data") == 0)
78            {
79                kernelInput.dataSize = secSize;
80                kernelInput.data = innerBin->getSectionContent(j);
81                dataFound = true;
82            }
83           
84            if (codeFound && dataFound)
85                break; // end of finding
86        }
87       
88        if ((flags & DISASM_CALNOTES) != 0)
89        {
90            // get ATI CAL notes
91            kernelInput.calNotes.resize(innerBin->getCALNotesNum(encEntryIndex));
92            cxuint j = 0;
93            for (const CALNote& calNote: innerBin->getCALNotes(encEntryIndex))
94            {
95                CALNoteInput& outCalNote = kernelInput.calNotes[j++];
96                outCalNote.header.nameSize = ULEV(calNote.header->nameSize);
97                outCalNote.header.type = ULEV(calNote.header->type);
98                outCalNote.header.descSize = ULEV(calNote.header->descSize);
99                std::copy(calNote.header->name, calNote.header->name+8,
100                          outCalNote.header.name);
101                outCalNote.data = calNote.data;
102            }
103        }
104    }
105}
106
107// template for handling 32-bit and 64-bit bnaries
108template<typename AmdMainBinary>
109static AmdDisasmInput* getAmdDisasmInputFromBinary(const AmdMainBinary& binary,
110           Flags flags)
111{
112    std::unique_ptr<AmdDisasmInput> input(new AmdDisasmInput);
113    input->is64BitMode = (binary.getHeader().e_ident[EI_CLASS] == ELFCLASS64);
114   
115    // get global setup (device, compile options, driver info, ...)
116    input->deviceType = binary.determineGPUDeviceType();
117    input->compileOptions = binary.getCompileOptions();
118    input->driverInfo = binary.getDriverInfo();
119    input->globalDataSize = binary.getGlobalDataSize();
120    input->globalData = binary.getGlobalData();
121    const size_t kernelInfosNum = binary.getKernelInfosNum();
122    const size_t kernelHeadersNum = binary.getKernelHeadersNum();
123    const size_t innerBinariesNum = binary.getInnerBinariesNum();
124    input->kernels.resize(kernelInfosNum);
125   
126    const Flags innerFlags = flags |
127        (((flags&DISASM_CONFIG)!=0) ? DISASM_METADATA|DISASM_CALNOTES : 0);
128    for (cxuint i = 0; i < kernelInfosNum; i++)
129    {
130        const KernelInfo& kernelInfo = binary.getKernelInfo(i);
131        const AmdInnerGPUBinary32* innerBin = nullptr;
132        if (i < innerBinariesNum)
133            innerBin = &binary.getInnerBinary(i);
134        if (innerBin == nullptr || innerBin->getKernelName() != kernelInfo.kernelName)
135        {
136            // fallback if not in order
137            try
138            { innerBin = &binary.getInnerBinary(kernelInfo.kernelName.c_str()); }
139            catch(const Exception& ex)
140            { innerBin = nullptr; }
141        }
142        AmdDisasmKernelInput& kernelInput = input->kernels[i];
143        // kernel metadata
144        kernelInput.metadataSize = binary.getMetadataSize(i);
145        kernelInput.metadata = binary.getMetadata(i);
146       
147        // kernel header
148        kernelInput.headerSize = 0;
149        kernelInput.header = nullptr;
150        const AmdGPUKernelHeader* khdr = nullptr;
151        if (i < kernelHeadersNum)
152            khdr = &binary.getKernelHeaderEntry(i);
153        if (khdr == nullptr || khdr->kernelName != kernelInfo.kernelName)
154        {
155            // fallback if not in order
156            try
157            { khdr = &binary.getKernelHeaderEntry(kernelInfo.kernelName.c_str()); }
158            catch(const Exception& ex) // failed
159            { khdr = nullptr; }
160        }
161        if (khdr != nullptr)
162        {
163            kernelInput.headerSize = khdr->size;
164            kernelInput.header = khdr->data;
165        }
166       
167        // get kernek input from inner binary
168        kernelInput.kernelName = kernelInfo.kernelName;
169        getAmdDisasmKernelInputFromBinary(innerBin, kernelInput, innerFlags,
170                  input->deviceType);
171    }
172    return input.release();
173}
174
175AmdDisasmInput* CLRX::getAmdDisasmInputFromBinary32(const AmdMainGPUBinary32& binary,
176                  Flags flags)
177{
178    return getAmdDisasmInputFromBinary(binary, flags);
179}
180
181AmdDisasmInput* CLRX::getAmdDisasmInputFromBinary64(const AmdMainGPUBinary64& binary,
182                  Flags flags)
183{
184    return getAmdDisasmInputFromBinary(binary, flags);
185}
186
187/* get AsmConfig */
188
189// AMD kernel argument types map (sorted by type names)
190const std::pair<const char*, KernelArgType> CLRX::disasmArgTypeNameMap[74] =
191{
192    { "char", KernelArgType::CHAR },
193    { "char16", KernelArgType::CHAR16 },
194    { "char2", KernelArgType::CHAR2 },
195    { "char3", KernelArgType::CHAR3 },
196    { "char4", KernelArgType::CHAR4 },
197    { "char8", KernelArgType::CHAR8 },
198    { "clk_event_t", KernelArgType::CLKEVENT },
199    { "counter32", KernelArgType::COUNTER32 },
200    { "double", KernelArgType::DOUBLE },
201    { "double16", KernelArgType::DOUBLE16 },
202    { "double2", KernelArgType::DOUBLE2 },
203    { "double3", KernelArgType::DOUBLE3 },
204    { "double4", KernelArgType::DOUBLE4 },
205    { "double8", KernelArgType::DOUBLE8 },
206    { "float", KernelArgType::FLOAT },
207    { "float16", KernelArgType::FLOAT16 },
208    { "float2", KernelArgType::FLOAT2 },
209    { "float3", KernelArgType::FLOAT3 },
210    { "float4", KernelArgType::FLOAT4 },
211    { "float8", KernelArgType::FLOAT8 },
212    { "image", KernelArgType::IMAGE },
213    { "image1d", KernelArgType::IMAGE1D },
214    { "image1d_array", KernelArgType::IMAGE1D_ARRAY },
215    { "image1d_buffer", KernelArgType::IMAGE1D_BUFFER },
216    { "image2d", KernelArgType::IMAGE2D },
217    { "image2d_array", KernelArgType::IMAGE2D_ARRAY },
218    { "image3d", KernelArgType::IMAGE3D },
219    { "int", KernelArgType::INT },
220    { "int16", KernelArgType::INT16 },
221    { "int2", KernelArgType::INT2 },
222    { "int3", KernelArgType::INT3 },
223    { "int4", KernelArgType::INT4 },
224    { "int8", KernelArgType::INT8 },
225    { "long", KernelArgType::LONG },
226    { "long16", KernelArgType::LONG16 },
227    { "long2", KernelArgType::LONG2 },
228    { "long3", KernelArgType::LONG3 },
229    { "long4", KernelArgType::LONG4 },
230    { "long8", KernelArgType::LONG8 },
231    { "pipe", KernelArgType::PIPE },
232    { "queue_t", KernelArgType::CMDQUEUE },
233    { "sampler_t", KernelArgType::SAMPLER },
234    { "short", KernelArgType::SHORT },
235    { "short16", KernelArgType::SHORT16 },
236    { "short2", KernelArgType::SHORT2 },
237    { "short3", KernelArgType::SHORT3 },
238    { "short4", KernelArgType::SHORT4 },
239    { "short8", KernelArgType::SHORT8 },
240    { "structure", KernelArgType::STRUCTURE },
241    { "uchar", KernelArgType::UCHAR },
242    { "uchar16", KernelArgType::UCHAR16 },
243    { "uchar2", KernelArgType::UCHAR2 },
244    { "uchar3", KernelArgType::UCHAR3 },
245    { "uchar4", KernelArgType::UCHAR4 },
246    { "uchar8", KernelArgType::UCHAR8 },
247    { "uint", KernelArgType::UINT },
248    { "uint16", KernelArgType::UINT16 },
249    { "uint2", KernelArgType::UINT2 },
250    { "uint3", KernelArgType::UINT3 },
251    { "uint4", KernelArgType::UINT4 },
252    { "uint8", KernelArgType::UINT8 },
253    { "ulong", KernelArgType::ULONG},
254    { "ulong16", KernelArgType::ULONG16 },
255    { "ulong2", KernelArgType::ULONG2 },
256    { "ulong3", KernelArgType::ULONG3 },
257    { "ulong4", KernelArgType::ULONG4 },
258    { "ulong8", KernelArgType::ULONG8 },
259    { "ushort", KernelArgType::USHORT },
260    { "ushort16", KernelArgType::USHORT16 },
261    { "ushort2", KernelArgType::USHORT2 },
262    { "ushort3", KernelArgType::USHORT3 },
263    { "ushort4", KernelArgType::USHORT4 },
264    { "ushort8", KernelArgType::USHORT8 },
265    { "void", KernelArgType::VOID }
266};
267
268static const size_t disasmArgTypeNameMapLength =
269        sizeof(disasmArgTypeNameMap)/sizeof(std::pair<const char*, KernelArgType>);
270
271// GPU argument type table
272const KernelArgType gpuArgTypeTable[] =
273{
274    KernelArgType::UCHAR,
275    KernelArgType::UCHAR2,
276    KernelArgType::UCHAR3,
277    KernelArgType::UCHAR4,
278    KernelArgType::UCHAR8,
279    KernelArgType::UCHAR16,
280    KernelArgType::CHAR,
281    KernelArgType::CHAR2,
282    KernelArgType::CHAR3,
283    KernelArgType::CHAR4,
284    KernelArgType::CHAR8,
285    KernelArgType::CHAR16,
286    KernelArgType::USHORT,
287    KernelArgType::USHORT2,
288    KernelArgType::USHORT3,
289    KernelArgType::USHORT4,
290    KernelArgType::USHORT8,
291    KernelArgType::USHORT16,
292    KernelArgType::SHORT,
293    KernelArgType::SHORT2,
294    KernelArgType::SHORT3,
295    KernelArgType::SHORT4,
296    KernelArgType::SHORT8,
297    KernelArgType::SHORT16,
298    KernelArgType::UINT,
299    KernelArgType::UINT2,
300    KernelArgType::UINT3,
301    KernelArgType::UINT4,
302    KernelArgType::UINT8,
303    KernelArgType::UINT16,
304    KernelArgType::INT,
305    KernelArgType::INT2,
306    KernelArgType::INT3,
307    KernelArgType::INT4,
308    KernelArgType::INT8,
309    KernelArgType::INT16,
310    KernelArgType::ULONG,
311    KernelArgType::ULONG2,
312    KernelArgType::ULONG3,
313    KernelArgType::ULONG4,
314    KernelArgType::ULONG8,
315    KernelArgType::ULONG16,
316    KernelArgType::LONG,
317    KernelArgType::LONG2,
318    KernelArgType::LONG3,
319    KernelArgType::LONG4,
320    KernelArgType::LONG8,
321    KernelArgType::LONG16,
322    KernelArgType::FLOAT,
323    KernelArgType::FLOAT2,
324    KernelArgType::FLOAT3,
325    KernelArgType::FLOAT4,
326    KernelArgType::FLOAT8,
327    KernelArgType::FLOAT16,
328    KernelArgType::DOUBLE,
329    KernelArgType::DOUBLE2,
330    KernelArgType::DOUBLE3,
331    KernelArgType::DOUBLE4,
332    KernelArgType::DOUBLE8,
333    KernelArgType::DOUBLE16
334};
335
336static const cxuint vectorIdTable[17] =
337{ UINT_MAX, 0, 1, 2, 3, UINT_MAX, UINT_MAX, UINT_MAX, 4,
338  UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, 5 };       
339
340// determine kernel argument type from type name from metadata line
341static KernelArgType determineKernelArgType(const char* typeString, cxuint vectorSize,
342                    LineNo lineNo)
343{
344    KernelArgType outType;
345   
346    if (vectorSize > 16)
347        throw ParseException(lineNo, "Wrong vector size");
348    const cxuint vectorId = vectorIdTable[vectorSize];
349    if (vectorId == UINT_MAX)
350        throw ParseException(lineNo, "Wrong vector size");
351   
352    if (::strncmp(typeString, "float:", 6) == 0)
353        outType = gpuArgTypeTable[8*6+vectorId];
354    else if (::strncmp(typeString, "double:", 7) == 0)
355        outType = gpuArgTypeTable[9*6+vectorId];
356    else if ((typeString[0] == 'i' || typeString[0] == 'u'))
357    {
358        /* indexBase - choose between unsigned/signed */
359        const cxuint indexBase = (typeString[0] == 'i')?6:0;
360        if (typeString[1] == '8')
361        {
362            if (typeString[2] != ':')
363                throw ParseException(lineNo, "Can't parse type");
364            outType = gpuArgTypeTable[indexBase+vectorId];
365        }
366        else
367        {
368            if (typeString[1] == '1' && typeString[2] == '6')
369                outType = gpuArgTypeTable[indexBase+2*6+vectorId];
370            else if (typeString[1] == '3' && typeString[2] == '2')
371                outType = gpuArgTypeTable[indexBase+4*6+vectorId];
372            else if (typeString[1] == '6' && typeString[2] == '4')
373                outType = gpuArgTypeTable[indexBase+6*6+vectorId];
374            else // if not determined
375                throw ParseException(lineNo, "Can't parse type");
376            if (typeString[3] != ':')
377                throw ParseException(lineNo, "Can't parse type");
378        }
379    }
380    else
381        throw ParseException(lineNo, "Can't parse type");
382   
383    return outType;
384}
385
386// find char to end
387inline static const char* strechr(const char* str, const char* end, int c)
388{
389    const char* p = str;
390    while (p!=end && *p != c && *p != 0) p++;
391    return (p!=end && *p==c) ? p : nullptr;
392}
393
394inline static int strnecmp(const char* str1, const char* str2, size_t n, const char* end)
395{
396    if (str1+n > end) return -1;
397    return strncmp(str1, str2, n);
398}
399
400
401/* get configuration to human readable form */
402static AmdKernelConfig getAmdKernelConfig(size_t metadataSize, const char* metadata,
403            const std::vector<CALNoteInput>& calNotes, const CString& driverInfo,
404            const cxbyte* kernelHeader, GPUArchitecture arch)
405{
406    cxuint driverVersion = 9999909U;
407    {
408        // parse version
409        size_t pos = driverInfo.find("AMD-APP"); // find AMDAPP
410        try
411        {
412            if (pos != std::string::npos)
413            {
414                /* let to parse version number */
415                pos += 9;
416                const char* end;
417                driverVersion = cstrtovCStyle<cxuint>(
418                        driverInfo.c_str()+pos, nullptr, end)*100;
419                end++;
420                driverVersion += cstrtovCStyle<cxuint>(end, nullptr, end);
421            }
422        }
423        catch(const ParseException& ex)
424        { driverVersion = 99999909U; /* newest possible */ }
425    }
426   
427    AmdKernelConfig config{};
428    std::vector<cxuint> argUavIds;
429    std::unordered_map<cxuint,cxuint> argCbIds;
430    std::unordered_map<CString, cxuint> argIndexMap;
431    std::vector<cxuint> samplerArgIndices;
432    std::vector<cxuint> constArgIndices;
433    // set as defaults
434    config.dimMask = BINGEN_DEFAULT;
435    config.printfId = BINGEN_DEFAULT;
436    config.constBufferId = BINGEN_DEFAULT;
437    config.uavPrivate = BINGEN_DEFAULT;
438    config.uavId = BINGEN_DEFAULT;
439    config.privateId = BINGEN_DEFAULT;
440    config.hwRegion = BINGEN_DEFAULT;
441    config.exceptions = 0;
442    config.usePrintf = ((ULEV(reinterpret_cast<const uint32_t*>(
443                kernelHeader)[4]) & 2) != 0);
444    config.tgSize = config.useConstantData = false;
445    config.reqdWorkGroupSize[0] = config.reqdWorkGroupSize[1] =
446            config.reqdWorkGroupSize[2] = 0;
447   
448    std::vector<cxuint> woImageIds;
449    cxuint argSamplers = 0;
450   
451    cxuint uavIdToCompare = 0;
452    /* parse arguments from metadata string */
453    /* this is very similar code as in AmdBinaries, but
454     * includes type and all needed argument attributes */
455    const char* linePtr = metadata;
456    const char* mtEnd = metadata + metadataSize;
457    LineNo lineNo = 1;
458    for (; linePtr != mtEnd; lineNo++)
459    {
460        const char* lineEnd = linePtr;
461        while (lineEnd!=mtEnd && *lineEnd!='\n') lineEnd++;
462        const char* outEnd;
463        // local size
464        if (::strnecmp(linePtr, ";memory:hwlocal:", 16, lineEnd)==0)
465            config.hwLocalSize = cstrtovCStyle<size_t>(linePtr+16, lineEnd, outEnd);
466        // hw region
467        else if (::strnecmp(linePtr, ";memory:hwregion:", 17, lineEnd)==0)
468            config.hwRegion = cstrtovCStyle<uint32_t>(linePtr+17, lineEnd, outEnd);
469        else if (::strnecmp(linePtr, ";cws:", 5, lineEnd)==0)
470        { 
471            // cws (reqd_work_group_size)
472            config.reqdWorkGroupSize[0] = cstrtovCStyle<uint32_t>(
473                        linePtr+5, lineEnd, outEnd);
474            if (outEnd==lineEnd || *outEnd!=':')
475                throw ParseException(lineNo, "Can't parse CWS");
476            outEnd++;
477            config.reqdWorkGroupSize[1] = cstrtovCStyle<uint32_t>(
478                        outEnd, lineEnd, outEnd);
479            if (outEnd==lineEnd || *outEnd!=':')
480                throw ParseException(lineNo, "Can't parse CWS");
481            outEnd++;
482            config.reqdWorkGroupSize[2] = cstrtovCStyle<uint32_t>(
483                        outEnd, lineEnd, outEnd);
484        }
485        else if (::strnecmp(linePtr, ";value:", 7, lineEnd)==0)
486        {
487            /* scalar value or structure */
488            AmdKernelArgInput arg;
489            const char* ptr = strechr(linePtr+7, lineEnd, ':');
490            if (ptr==nullptr)
491                throw ParseException(lineNo, "Can't parse value argument");
492            arg.argName.assign(linePtr+7, ptr);
493            arg.argType = KernelArgType::VOID;
494            arg.pointerType = KernelArgType::VOID;
495            arg.ptrSpace = KernelPtrSpace::NONE;
496            arg.resId = BINGEN_DEFAULT;
497            arg.ptrAccess = 0;
498            arg.structSize = 0;
499            arg.constSpaceSize = 0;
500            arg.resId = 0;
501            arg.used = true;
502            ptr++;
503            const char* nextPtr = strechr(ptr, lineEnd, ':');
504            if (nextPtr==nullptr)
505                throw ParseException(lineNo, "Can't parse value argument");
506            const char* typeStr = ptr;
507            ptr = nextPtr+1;
508            if (::strncmp(typeStr, "struct:", 7)==0)
509            {
510                // argument is structure
511                arg.argType = KernelArgType::STRUCTURE;
512                arg.structSize = cstrtovCStyle<uint32_t>(ptr, lineEnd, outEnd);
513            }
514            else
515            {
516                // regular type
517                nextPtr = strechr(ptr, lineEnd, ':');
518                if (nextPtr==nullptr)
519                    throw ParseException(lineNo, "Can't parse value argument");
520                nextPtr++;
521                cxuint vectorSize = cstrtoui(ptr, lineEnd, outEnd);
522                arg.argType = determineKernelArgType(typeStr, vectorSize, lineNo);
523            }
524            argUavIds.push_back(0);
525            argIndexMap[arg.argName] = config.args.size();
526            config.args.push_back(arg);
527        }
528        else if (::strnecmp(linePtr, ";pointer:", 9, lineEnd)==0)
529        {
530            /* pointer (local, global, constant */
531            AmdKernelArgInput arg;
532            const char* ptr = strechr(linePtr+9, lineEnd, ':');
533            if (ptr==nullptr)
534                throw ParseException(lineNo, "Can't parse pointer argument");
535            arg.argName.assign(linePtr+9, ptr);
536            arg.argType = KernelArgType::POINTER;
537            arg.pointerType = KernelArgType::VOID;
538            arg.ptrSpace = KernelPtrSpace::NONE;
539            arg.ptrAccess = 0;
540            arg.structSize = 0;
541            arg.constSpaceSize = 0;
542            arg.resId = BINGEN_DEFAULT;
543            arg.used = true;
544            ptr++;
545            const char* nextPtr = strechr(ptr, lineEnd, ':');
546            if (nextPtr==nullptr)
547                throw ParseException(lineNo, "Can't parse pointer argument");
548            const char* typeName = ptr;
549            const char* typeNameEnd = nextPtr;
550            ptr = nextPtr;
551            //ptr += 5; // to argOffset
552            ptr++;
553            ptr = strechr(ptr, lineEnd, ':');
554            ptr++;
555            ptr = strechr(ptr, lineEnd, ':');
556            ptr++;
557            ptr = strechr(ptr, lineEnd, ':');
558            if (ptr==nullptr)
559                throw ParseException(lineNo, "Can't parse pointer argument");
560            ptr++;
561            // qualifier
562            if (::strnecmp(ptr, "uav:", 4, lineEnd) == 0)
563                arg.ptrSpace = KernelPtrSpace::GLOBAL;
564            else if (::strnecmp(ptr, "hc:", 3, lineEnd) == 0 ||
565                        ::strnecmp(ptr, "c:", 2, lineEnd) == 0)
566                arg.ptrSpace = KernelPtrSpace::CONSTANT;
567            else if (::strnecmp(ptr, "hl:", 3, lineEnd) == 0)
568                arg.ptrSpace = KernelPtrSpace::LOCAL;
569            else
570                throw ParseException(lineNo, "Can't parse pointer space");
571            ptr = strechr(ptr, lineEnd, ':');
572            if (ptr==nullptr)
573                throw ParseException(lineNo, "Can't parse pointer argument");
574            ptr++;
575            arg.resId = cstrtovCStyle<uint32_t>(ptr, lineEnd, outEnd);
576           
577            if (arg.ptrSpace == KernelPtrSpace::CONSTANT)
578                argCbIds[arg.resId] = config.args.size();
579           
580            argUavIds.push_back(arg.resId);
581            //arg.resId = AMDBIN_DEFAULT;
582            ptr = strechr(ptr, lineEnd, ':');
583            if (ptr==nullptr)
584                throw ParseException(lineNo, "Can't parse pointer argument");
585            ptr++;
586            if (::strnecmp(typeName, "opaque:", 7, typeNameEnd+1)==0)
587                arg.pointerType = KernelArgType::STRUCTURE;
588            else if (::strnecmp(typeName, "struct:", 7, typeNameEnd+1)==0)
589            {
590                arg.pointerType = KernelArgType::STRUCTURE;
591                arg.structSize = cstrtovCStyle<uint32_t>(ptr, lineEnd, outEnd);
592            }
593            ptr = strechr(ptr, lineEnd, ':');
594           
595            if (ptr==nullptr)
596                throw ParseException(lineNo, "Can't parse pointer argument");
597            ptr++;
598            // access qualifier
599            if (::strnecmp(ptr, "RO:", 2, lineEnd)==0 &&
600                    arg.ptrSpace==KernelPtrSpace::GLOBAL)
601                arg.ptrAccess |= KARG_PTR_CONST;
602            else if (::strnecmp(ptr, "RW:", 2, lineEnd) == 0)
603                arg.ptrAccess |= KARG_PTR_NORMAL;
604           
605            ptr = strechr(ptr, lineEnd, ':');
606            if (ptr==nullptr || ptr+2>=lineEnd)
607                throw ParseException(lineNo, "Can't parse pointer argument");
608            ptr++;
609            // volatile
610            if (*ptr == '1')
611                arg.ptrAccess |= KARG_PTR_VOLATILE;
612            ptr++;
613            // restrict
614            if (ptr+1>=lineEnd || *ptr!=':')
615                throw ParseException(lineNo, "Can't parse pointer argument");
616            ptr++;
617            if (*ptr == '1')
618                arg.ptrAccess |= KARG_PTR_RESTRICT;
619            argIndexMap[arg.argName] = config.args.size();
620            config.args.push_back(arg);
621        }
622        else if (::strnecmp(linePtr, ";image:", 7, lineEnd)==0)
623        {
624            /* parse image argument entry */
625            AmdKernelArgInput arg;
626            const char* ptr = strechr(linePtr+7, lineEnd, ':');
627            if (ptr==nullptr)
628                throw ParseException(lineNo, "Can't parse image argument");
629            arg.argName.assign(linePtr+7, ptr);
630            arg.pointerType = KernelArgType::VOID;
631            arg.ptrSpace = KernelPtrSpace::NONE;
632            arg.resId = BINGEN_DEFAULT;
633            arg.ptrAccess = 0;
634            arg.structSize = 0;
635            arg.constSpaceSize = 0;
636            arg.used = true;
637            ptr++;
638            const char* nextPtr = strechr(ptr, lineEnd, ':');
639            if (nextPtr==nullptr)
640                throw ParseException(lineNo, "Can't parse image argument");
641            const char* imgType = ptr;
642            const char* imgTypeEnd = nextPtr;
643            ptr = nextPtr+1;
644            // parse type of image
645            if (::strnecmp(imgType, "1D:", 3, imgTypeEnd+1)==0)
646                arg.argType = KernelArgType::IMAGE1D;
647            else if (::strnecmp(imgType, "1DA:", 4, imgTypeEnd+1)==0)
648                arg.argType = KernelArgType::IMAGE1D_ARRAY;
649            else if (::strnecmp(imgType, "1DB:", 4, imgTypeEnd+1)==0)
650                arg.argType = KernelArgType::IMAGE1D_BUFFER;
651            else if (::strnecmp(imgType, "2D:", 3, imgTypeEnd+1)==0)
652                arg.argType = KernelArgType::IMAGE2D;
653            else if (::strnecmp(imgType, "2DA:", 4, imgTypeEnd+1)==0)
654                arg.argType = KernelArgType::IMAGE2D_ARRAY;
655            else if (::strnecmp(imgType, "3D:", 3, imgTypeEnd+1)==0)
656                arg.argType = KernelArgType::IMAGE3D;
657            else
658                throw ParseException(lineNo, "Can't parse image type");
659            // image access qualifier
660            if (::strnecmp(ptr,"RO:", 3, lineEnd) == 0)
661                arg.ptrAccess |= KARG_PTR_READ_ONLY;
662            else if (::strnecmp(ptr,"WO:", 3, lineEnd) == 0)
663            {
664                arg.ptrAccess |= KARG_PTR_WRITE_ONLY;
665                woImageIds.push_back(config.args.size());
666            }
667            else
668                throw ParseException(lineNo, "Can't parse image access");
669            ptr += 3;
670            arg.resId = cstrtovCStyle<uint32_t>(ptr, lineEnd, outEnd);
671            argUavIds.push_back(0);
672            argIndexMap[arg.argName] = config.args.size();
673            config.args.push_back(arg);
674        }
675        else if (::strnecmp(linePtr, ";counter:", 9, lineEnd)==0)
676        {
677            /* counter */
678            AmdKernelArgInput arg;
679            const char* ptr = strechr(linePtr+9, lineEnd, ':');
680            if (ptr==nullptr)
681                throw ParseException(lineNo, "Can't parse counter argument");
682            arg.argName.assign(linePtr+9, ptr);
683            arg.argType = KernelArgType::COUNTER32;
684            arg.pointerType = KernelArgType::VOID;
685            arg.ptrSpace = KernelPtrSpace::NONE;
686            ptr++; // skip ':'
687            if (::strnecmp(ptr, "32:", 3, lineEnd)!=0)
688                throw ParseException(lineNo, "Can't parse counter argument");
689            ptr+=3; // '32:'
690            arg.resId = cstrtovCStyle<uint32_t>(ptr, lineEnd, outEnd);
691            arg.ptrAccess = 0;
692            arg.structSize = 0;
693            arg.constSpaceSize = 0;
694            arg.used = true;
695            argUavIds.push_back(0);
696            argIndexMap[arg.argName] = config.args.size();
697            config.args.push_back(arg);
698        }
699        else if (::strnecmp(linePtr, ";constarg:", 10, lineEnd)==0)
700        {
701            /* constant argument to apply constant qualifier */
702            cxuint argNo = cstrtovCStyle<cxuint>(linePtr+10, lineEnd, outEnd);
703            constArgIndices.push_back(argNo);
704        }
705        else if (::strnecmp(linePtr, ";sampler:", 9, lineEnd)==0)
706        {
707            /* image sampler */
708            const char* ptr = strechr(linePtr+9, lineEnd, ':');
709            if (ptr==nullptr)
710                throw ParseException(lineNo, "Can't parse sampler entry");
711            std::string samplerName(linePtr+9, ptr);
712            if (samplerName.compare(0, 8, "unknown_") == 0)
713            {
714                // add sampler
715                ptr++;
716                cxuint sampId = cstrtovCStyle<cxuint>(ptr, lineEnd, outEnd);
717                ptr = strechr(ptr, lineEnd, ':');
718                if (ptr==nullptr)
719                    throw ParseException(lineNo, "Can't parse sampler entry");
720                ptr += 3;
721                cxuint value = cstrtovCStyle<cxuint>(ptr, lineEnd, outEnd);
722                if (config.samplers.size() < sampId+1)
723                    config.samplers.resize(sampId+1);
724                config.samplers[sampId] = value;
725            }
726            else
727            {
728                // this argument's sampler
729                auto it = argIndexMap.find(samplerName);
730                if (it!=argIndexMap.end())
731                    samplerArgIndices.push_back(it->second);
732                argSamplers++;
733            }
734        }
735        else if (::strnecmp(linePtr, ";reflection:", 12, lineEnd)==0)
736        {
737            /* reflection that have type name */
738            cxuint argNo = cstrtovCStyle<cxuint>(linePtr+12, lineEnd, outEnd);
739            if (argNo >= config.args.size())
740                throw DisasmException("ArgNo out of range");
741            const char* ptr = strechr(linePtr+12, lineEnd, ':');
742            if (ptr==nullptr)
743                throw ParseException(lineNo, "Can't parse reflection entry");
744            ptr++;
745            AmdKernelArgInput& arg = config.args[argNo];
746            arg.typeName.assign(ptr, lineEnd);
747            /* determine type */
748            if (arg.argType == KernelArgType::POINTER &&
749                arg.pointerType == KernelArgType::VOID)
750            {
751                // get type name from reflection and find name from type name
752                CString ptrTypeName = arg.typeName.substr(0, arg.typeName.size()-1);
753                auto it = binaryMapFind(disasmArgTypeNameMap, 
754                        disasmArgTypeNameMap+disasmArgTypeNameMapLength,
755                        ptrTypeName.c_str(), CStringLess());
756               
757                if (it != disasmArgTypeNameMap+disasmArgTypeNameMapLength)
758                    arg.pointerType = it->second;
759                // treat enum as unsigned integer
760                else if (arg.typeName.compare(0, 5, "enum ")==0)
761                    arg.pointerType = KernelArgType::UINT;
762            }
763            //else
764        }
765        else if (::strnecmp(linePtr, ";uavid:", 7, lineEnd)==0)
766        {
767            cxuint uavId = cstrtovCStyle<cxuint>(linePtr+7, lineEnd, outEnd);
768            uavIdToCompare = uavId;
769            if (driverVersion < 134805)
770                uavIdToCompare = 9;
771        }
772        // get printfif
773        else if (::strnecmp(linePtr, ";printfid:", 10, lineEnd)==0)
774            config.printfId = cstrtovCStyle<cxuint>(linePtr+10, lineEnd, outEnd);
775        // get privateid
776        else if (::strnecmp(linePtr, ";privateid:", 11, lineEnd)==0)
777            config.privateId = cstrtovCStyle<cxuint>(linePtr+11, lineEnd, outEnd);
778        else if (::strnecmp(linePtr, ";cbid:", 6, lineEnd)==0)
779            config.constBufferId= cstrtovCStyle<cxuint>(linePtr+6, lineEnd, outEnd);
780        else if (::strnecmp(linePtr, ";memory:uavprivate:", 19, lineEnd)==0)
781            config.uavPrivate = cstrtovCStyle<cxuint>(linePtr+19, lineEnd, outEnd);
782        // to next line
783        linePtr = (lineEnd!=mtEnd) ? lineEnd+1 : lineEnd;
784    }
785   
786    if (argSamplers != 0 && !config.samplers.empty())
787    {
788        // get sampler's values
789        for (cxuint k = argSamplers; k < config.samplers.size(); k++)
790            config.samplers[k-argSamplers] = config.samplers[k];
791        config.samplers.resize(config.samplers.size()-argSamplers);
792    }
793    // set sampler type to some arguments (if they are samplers)
794    for (cxuint argIdx: samplerArgIndices)
795        if (argIdx < config.args.size())
796            config.args[argIdx].argType = KernelArgType::SAMPLER;
797        else
798            throw DisasmException("Sampler arg index out of range");
799   
800    // apply const qualifier to some pointer arguments
801    for (cxuint argIdx: constArgIndices)
802        if (argIdx < config.args.size())
803            config.args[argIdx].ptrAccess |= KARG_PTR_CONST;
804        else
805            throw DisasmException("Const arg index out of range");
806   
807    /* from ATI CAL NOTES */
808    cxbyte uavMask[128];
809    std::fill(uavMask, uavMask+128, cxbyte(0));
810    for (const CALNoteInput& calNoteInput: calNotes)
811    {
812        const CALNoteHeader& cnHdr = calNoteInput.header;
813        const cxbyte* cnData = calNoteInput.data;
814       
815        switch (cnHdr.type)
816        {
817            case CALNOTE_ATI_SCRATCH_BUFFERS:
818                config.scratchBufferSize =
819                        (ULEV(*reinterpret_cast<const uint32_t*>(cnData))<<2);
820                break;
821            case CALNOTE_ATI_CONSTANT_BUFFERS:
822                if (driverVersion < 112402)
823                {
824                    // older drivers holds info about constant buffer in that CALNote
825                    const CALConstantBufferMask* cbMask =
826                            reinterpret_cast<const CALConstantBufferMask*>(cnData);
827                    const cxuint entriesNum = cnHdr.descSize/sizeof(CALConstantBufferMask);
828                    for (cxuint k = 0; k < entriesNum; k++)
829                    {
830                        if (argCbIds.find(ULEV(cbMask[k].index)) == argCbIds.end())
831                            continue;
832                        config.args[argCbIds[ULEV(cbMask[k].index)]].constSpaceSize =
833                                ULEV(cbMask[k].size)<<4;
834                    }
835                }
836                break;
837            case CALNOTE_ATI_CONDOUT:
838                config.condOut = ULEV(*reinterpret_cast<const uint32_t*>(cnData));
839                break;
840            case CALNOTE_ATI_EARLYEXIT:
841                config.earlyExit = ULEV(*reinterpret_cast<const uint32_t*>(cnData));
842                break;
843            case CALNOTE_ATI_PROGINFO:
844            {
845                // PROG INFO CAL notes
846                const CALProgramInfoEntry* piEntry =
847                        reinterpret_cast<const CALProgramInfoEntry*>(cnData);
848                const cxuint piEntriesNum = cnHdr.descSize/sizeof(CALProgramInfoEntry);
849                for (cxuint k = 0; k < piEntriesNum; k++)
850                {
851                    // determine type by address
852                    switch(ULEV(piEntry[k].address))
853                    {
854                        case 0x80001000:
855                            config.userDatas.resize(ULEV(piEntry[k].value));
856                            break;
857                        case 0x8000001f:
858                        {
859                            if (driverVersion >= 134805)
860                                config.useConstantData =
861                                        ((ULEV(piEntry[k].value) & 0x400) != 0);
862                            cxuint imgid = 0;
863                            for (cxuint woImg: woImageIds)
864                            {
865                                AmdKernelArgInput& imgArg = config.args[woImg];
866                                imgArg.used = ((ULEV(piEntry[k].value)&(1U<<imgid)) != 0);
867                                imgid++;
868                            }
869                            uavIdToCompare = ((ULEV(piEntry[k].value)&
870                                    (1U<<uavIdToCompare)) != 0)?0:uavIdToCompare;
871                            break;
872                        }
873                        case 0x80001041:
874                            config.usedVGPRsNum = ULEV(piEntry[k].value);
875                            break;
876                        case 0x80001042:
877                            config.usedSGPRsNum = ULEV(piEntry[k].value);
878                            break;
879                        case 0x80001043:
880                            config.floatMode = ULEV(piEntry[k].value);
881                            break;
882                        case 0x80001044:
883                            config.ieeeMode = ULEV(piEntry[k].value);
884                            break;
885                        case 0x00002e13:
886                        {
887                            // get PGM_RSRC2 value and set config values
888                            config.pgmRSRC2 = ULEV(piEntry[k].value);
889                            config.tgSize = (config.pgmRSRC2 & 0x400)!=0;
890                            config.exceptions = (config.pgmRSRC2>>24)&0x7f;
891                            config.dimMask = getDefaultDimMask(arch, config.pgmRSRC2);
892                            break;
893                        }
894                        default:
895                        {
896                            const uint32_t addr = ULEV(piEntry[k].address);
897                            const uint32_t val = ULEV(piEntry[k].value);
898                            if (addr >= 0x80001001 && addr < 0x80001041)
899                            {
900                                // if USER DATA's
901                                const cxuint elIndex = (addr-0x80001001)>>2;
902                                if (config.userDatas.size() <= elIndex)
903                                    continue; // ignore userdata beyond specified number
904                                switch (addr&3)
905                                {
906                                    // get DATA_CLASS, APISLOIT, REGSTART and REGEND
907                                    case 1:
908                                        config.userDatas[elIndex].dataClass = val;
909                                        break;
910                                    case 2:
911                                        config.userDatas[elIndex].apiSlot = val;
912                                        break;
913                                    case 3:
914                                        config.userDatas[elIndex].regStart = val;
915                                        break;
916                                    case 0:
917                                        config.userDatas[elIndex].regSize = val;
918                                        break;
919                                }
920                            }
921                            if (addr >= 0x80001843 && addr < 0x80001863)
922                            {
923                                // get uav mask from proginfo
924                                const cxuint elIndex = (addr-0x80001843)<<2;
925                                uavMask[elIndex] = val&0xff;
926                                uavMask[elIndex+1] = (val>>8)&0xff;
927                                uavMask[elIndex+2] = (val>>16)&0xff;
928                                uavMask[elIndex+3] = val>>24;
929                            }
930                        }
931                    }
932                }
933                break;
934            }
935        }
936    }
937    // check if argument is unused
938    cxuint k = 0;
939    for (AmdKernelArgInput& arg: config.args)
940    {
941        /* apply used flag for argument */
942        if (arg.argType == KernelArgType::POINTER &&
943            (arg.ptrSpace == KernelPtrSpace::GLOBAL ||
944             (arg.ptrSpace == KernelPtrSpace::CONSTANT && driverVersion >= 134805)) &&
945                 (uavMask[argUavIds[k]>>3] & (1U<<(argUavIds[k]&7))) == 0)
946            arg.used = false;
947        k++;
948    }
949   
950    config.uavId = uavIdToCompare;
951    return config;
952}
953
954// AMD CAL notes table by CAL note type
955static const char* disasmCALNoteNamesTable[] =
956{
957    ".proginfo",
958    ".inputs",
959    ".outputs",
960    ".condout",
961    ".floatconsts",
962    ".intconsts",
963    ".boolconsts",
964    ".earlyexit",
965    ".globalbuffers",
966    ".constantbuffers",
967    ".inputsamplers",
968    ".persistentbuffers",
969    ".scratchbuffers",
970    ".subconstantbuffers",
971    ".uavmailboxsize",
972    ".uav",
973    ".uavopmask"
974};
975
976/* dump kernel configuration in machine readable form */
977static void dumpAmdKernelDatas(std::ostream& output, const AmdDisasmKernelInput& kinput,
978       Flags flags)
979{
980    if ((flags & DISASM_METADATA) != 0)
981    {
982        if (kinput.header != nullptr && kinput.headerSize != 0)
983        {
984            // if kernel header available
985            output.write("    .header\n", 12);
986            printDisasmData(kinput.headerSize, kinput.header, output, true);
987        }
988        if (kinput.metadata != nullptr && kinput.metadataSize != 0)
989        {
990            // if kernel metadata available
991            output.write("    .metadata\n", 14);
992            printDisasmLongString(kinput.metadataSize, kinput.metadata, output, true);
993        }
994    }
995    if ((flags & DISASM_DUMPDATA) != 0 && kinput.data != nullptr && kinput.dataSize != 0)
996    {
997        // if kernel data available
998        output.write("    .data\n", 10);
999        printDisasmData(kinput.dataSize, kinput.data, output, true);
1000    }
1001   
1002    if ((flags & DISASM_CALNOTES) != 0)
1003        for (const CALNoteInput& calNote: kinput.calNotes)
1004        {
1005            char buf[80];
1006            // calNote.header fields is already in native endian
1007            if (calNote.header.type != 0 && calNote.header.type <= CALNOTE_ATI_MAXTYPE)
1008            {
1009                output.write("    ", 4);
1010                output.write(disasmCALNoteNamesTable[calNote.header.type-1],
1011                             ::strlen(disasmCALNoteNamesTable[calNote.header.type-1]));
1012            }
1013            else
1014            {
1015                // unknown CAL note type
1016                const size_t len = itocstrCStyle(calNote.header.type, buf, 32, 16);
1017                output.write("    .calnote ", 13);
1018                output.write(buf, len);
1019            }
1020           
1021            if (calNote.data == nullptr || calNote.header.descSize==0)
1022            {
1023                output.put('\n');
1024                continue; // skip if no data
1025            }
1026           
1027            switch(calNote.header.type)
1028            {
1029                // handle CAL note types
1030                case CALNOTE_ATI_PROGINFO:
1031                {
1032                    // print cal notes as prog info entries
1033                    output.put('\n');
1034                    const cxuint progInfosNum =
1035                            calNote.header.descSize/sizeof(CALProgramInfoEntry);
1036                    const CALProgramInfoEntry* progInfos =
1037                        reinterpret_cast<const CALProgramInfoEntry*>(calNote.data);
1038                    ::memcpy(buf, "        .entry ", 15);
1039                    for (cxuint k = 0; k < progInfosNum; k++)
1040                    {
1041                        // format: .proginfo address, value
1042                        const CALProgramInfoEntry& progInfo = progInfos[k];
1043                        size_t bufPos = 15 + itocstrCStyle(ULEV(progInfo.address),
1044                                     buf+15, 32, 16, 8);
1045                        buf[bufPos++] = ',';
1046                        buf[bufPos++] = ' ';
1047                        bufPos += itocstrCStyle(ULEV(progInfo.value),
1048                                  buf+bufPos, 32, 16, 8);
1049                        buf[bufPos++] = '\n';
1050                        output.write(buf, bufPos);
1051                    }
1052                    /// rest
1053                    printDisasmData(calNote.header.descSize -
1054                            progInfosNum*sizeof(CALProgramInfoEntry),
1055                            calNote.data + progInfosNum*sizeof(CALProgramInfoEntry),
1056                            output, true);
1057                    break;
1058                }
1059                case CALNOTE_ATI_INPUTS:
1060                case CALNOTE_ATI_OUTPUTS:
1061                case CALNOTE_ATI_GLOBAL_BUFFERS:
1062                case CALNOTE_ATI_SCRATCH_BUFFERS:
1063                case CALNOTE_ATI_PERSISTENT_BUFFERS:
1064                    output.put('\n');
1065                    printDisasmDataU32(calNote.header.descSize>>2,
1066                           reinterpret_cast<const uint32_t*>(calNote.data),
1067                           output, true);
1068                    printDisasmData(calNote.header.descSize&3,
1069                           calNote.data + (calNote.header.descSize&~3U), output, true);
1070                    break;
1071                case CALNOTE_ATI_INT32CONSTS:
1072                case CALNOTE_ATI_FLOAT32CONSTS:
1073                case CALNOTE_ATI_BOOL32CONSTS:
1074                {
1075                    // print cal notes as segment list
1076                    output.put('\n');
1077                    const cxuint segmentsNum =
1078                            calNote.header.descSize/sizeof(CALDataSegmentEntry);
1079                    const CALDataSegmentEntry* segments =
1080                            reinterpret_cast<const CALDataSegmentEntry*>(calNote.data);
1081                    ::memcpy(buf, "        .segment ", 17);
1082                    for (cxuint k = 0; k < segmentsNum; k++)
1083                    {
1084                        const CALDataSegmentEntry& segment = segments[k];
1085                        // format: .segment offset, size
1086                        size_t bufPos = 17 + itocstrCStyle(
1087                                    ULEV(segment.offset), buf + 17, 32);
1088                        buf[bufPos++] = ',';
1089                        buf[bufPos++] = ' ';
1090                        bufPos += itocstrCStyle(ULEV(segment.size), buf+bufPos, 32);
1091                        buf[bufPos++] = '\n';
1092                        output.write(buf, bufPos);
1093                    }
1094                    /// rest
1095                    printDisasmData(calNote.header.descSize -
1096                            segmentsNum*sizeof(CALDataSegmentEntry),
1097                            calNote.data + segmentsNum*sizeof(CALDataSegmentEntry),
1098                            output, true);
1099                    break;
1100                }
1101                case CALNOTE_ATI_INPUT_SAMPLERS:
1102                {
1103                    // print cal notes as sampler list
1104                    output.put('\n');
1105                    const cxuint samplersNum =
1106                            calNote.header.descSize/sizeof(CALSamplerMapEntry);
1107                    const CALSamplerMapEntry* samplers =
1108                            reinterpret_cast<const CALSamplerMapEntry*>(calNote.data);
1109                    ::memcpy(buf, "        .sampler ", 17);
1110                    for (cxuint k = 0; k < samplersNum; k++)
1111                    {
1112                        const CALSamplerMapEntry& sampler = samplers[k];
1113                        // format: .sampler input, sampler
1114                        size_t bufPos = 17 + itocstrCStyle(
1115                                    ULEV(sampler.input), buf + 17, 32);
1116                        buf[bufPos++] = ',';
1117                        buf[bufPos++] = ' ';
1118                        bufPos += itocstrCStyle(ULEV(sampler.sampler),
1119                                    buf+bufPos, 32, 16);
1120                        buf[bufPos++] = '\n';
1121                        output.write(buf, bufPos);
1122                    }
1123                    /// rest
1124                    printDisasmData(calNote.header.descSize -
1125                            samplersNum*sizeof(CALSamplerMapEntry),
1126                            calNote.data + samplersNum*sizeof(CALSamplerMapEntry),
1127                            output, true);
1128                    break;
1129                }
1130                case CALNOTE_ATI_CONSTANT_BUFFERS:
1131                {
1132                    // print cal notes as cbmasks
1133                    output.put('\n');
1134                    const cxuint constBufMasksNum =
1135                            calNote.header.descSize/sizeof(CALConstantBufferMask);
1136                    const CALConstantBufferMask* constBufMasks =
1137                        reinterpret_cast<const CALConstantBufferMask*>(calNote.data);
1138                    ::memcpy(buf, "        .cbmask ", 16);
1139                    for (cxuint k = 0; k < constBufMasksNum; k++)
1140                    {
1141                        // format: .cbmask index, size
1142                        const CALConstantBufferMask& cbufMask = constBufMasks[k];
1143                        size_t bufPos = 16 + itocstrCStyle(
1144                                    ULEV(cbufMask.index), buf + 16, 32);
1145                        buf[bufPos++] = ',';
1146                        buf[bufPos++] = ' ';
1147                        bufPos += itocstrCStyle(ULEV(cbufMask.size), buf+bufPos, 32);
1148                        buf[bufPos++] = '\n';
1149                        output.write(buf, bufPos);
1150                    }
1151                    /// rest
1152                    printDisasmData(calNote.header.descSize -
1153                        constBufMasksNum*sizeof(CALConstantBufferMask),
1154                        calNote.data + constBufMasksNum*sizeof(CALConstantBufferMask),
1155                        output, true);
1156                    break;
1157                }
1158                case CALNOTE_ATI_EARLYEXIT:
1159                case CALNOTE_ATI_CONDOUT:
1160                case CALNOTE_ATI_UAV_OP_MASK:
1161                case CALNOTE_ATI_UAV_MAILBOX_SIZE:
1162                    if (calNote.header.descSize == 4)
1163                    {
1164                        const size_t len = itocstrCStyle(
1165                                ULEV(*reinterpret_cast<const uint32_t*>(
1166                                    calNote.data)), buf, 32);
1167                        output.put(' ');
1168                        output.write(buf, len);
1169                        output.put('\n');
1170                    }
1171                    else
1172                    {
1173                        // otherwise if size is not 4 bytes
1174                        output.put('\n');
1175                        printDisasmData(calNote.header.descSize,
1176                                calNote.data, output, true);
1177                    }
1178                    break;
1179                case CALNOTE_ATI_UAV:
1180                {
1181                    output.put('\n');
1182                    const cxuint uavsNum =
1183                            calNote.header.descSize/sizeof(CALUAVEntry);
1184                    const CALUAVEntry* uavEntries =
1185                        reinterpret_cast<const CALUAVEntry*>(calNote.data);
1186                    ::memcpy(buf, "        .entry ", 15);
1187                    for (cxuint k = 0; k < uavsNum; k++)
1188                    {
1189                        const CALUAVEntry& uavEntry = uavEntries[k];
1190                        /// uav entry format: .entry UAVID, F1, F2, TYPE
1191                        size_t bufPos = 15 + itocstrCStyle(
1192                                    ULEV(uavEntry.uavId), buf + 15, 32);
1193                        buf[bufPos++] = ',';
1194                        buf[bufPos++] = ' ';
1195                        bufPos += itocstrCStyle(ULEV(uavEntry.f1), buf+bufPos, 32);
1196                        buf[bufPos++] = ',';
1197                        buf[bufPos++] = ' ';
1198                        bufPos += itocstrCStyle(ULEV(uavEntry.f2), buf+bufPos, 32);
1199                        buf[bufPos++] = ',';
1200                        buf[bufPos++] = ' ';
1201                        bufPos += itocstrCStyle(ULEV(uavEntry.type), buf+bufPos, 32);
1202                        buf[bufPos++] = '\n';
1203                        output.write(buf, bufPos);
1204                    }
1205                    /// rest
1206                    printDisasmData(calNote.header.descSize -
1207                        uavsNum*sizeof(CALUAVEntry),
1208                        calNote.data + uavsNum*sizeof(CALUAVEntry), output, true);
1209                    break;
1210                }
1211                default:
1212                    output.put('\n');
1213                    printDisasmData(calNote.header.descSize, calNote.data,
1214                                    output, true);
1215                    break;
1216            }
1217        }
1218}
1219
1220// USER DATA class names by value
1221static const char* dataClassNameTbl[] =
1222{
1223    "imm_resource",
1224    "imm_sampler",
1225    "imm_const_buffer",
1226    "imm_vertex_buffer",
1227    "imm_uav",
1228    "imm_alu_float_const",
1229    "imm_alu_bool32_const",
1230    "imm_gds_counter_range",
1231    "imm_gds_memory_range",
1232    "imm_gws_base",
1233    "imm_work_item_range",
1234    "imm_work_group_range",
1235    "imm_dispatch_id",
1236    "imm_scratch_buffer",
1237    "imm_heap_buffer",
1238    "imm_kernel_arg",
1239    "sub_ptr_fetch_shader",
1240    "ptr_resource_table",
1241    "ptr_internal_resource_table",
1242    "ptr_sampler_table",
1243    "ptr_const_buffer_table",
1244    "ptr_vertex_buffer_table",
1245    "ptr_so_buffer_table",
1246    "ptr_uav_table",
1247    "ptr_internal_global_table",
1248    "ptr_extended_user_data",
1249    "ptr_indirect_resource",
1250    "ptr_indirect_internal_resource",
1251    "ptr_indirect_uav",
1252    "imm_context_base",
1253    "imm_lds_esgs_size",
1254    "imm_global_offset",
1255    "imm_generic_user_data"
1256};
1257
1258// kernel arg types table
1259static const char* kernelArgTypeNamesTbl[] =
1260{
1261    "void",
1262    "uchar", "char", "ushort", "short", "uint", "int", "ulong", "long", "float",
1263    "double", "", "image", "image1d", "image1d_array", "image1d_buffer", "image2d",
1264    "image2d_array", "image3d",
1265    "uchar2", "uchar3", "uchar4", "uchar8", "uchar16",
1266    "char2", "char3", "char4", "char8", "char16",
1267    "ushort2", "ushort3", "ushort4", "ushort8", "ushort16",
1268    "short2", "short3", "short4", "short8", "short16",
1269    "uint2", "uint3", "uint4", "uint8", "uint16",
1270    "int2", "int3", "int4", "int8", "int16",
1271    "ulong2", "ulong3", "ulong4", "ulong8", "ulong16",
1272    "long2", "long3", "long4", "long8", "long16",
1273    "float2", "float3", "float4", "float8", "float16",
1274    "double2", "double3", "double4", "double8", "double16",
1275    "sampler", "structure", "counter32", "counter64", "pipe", "queue", "clkevent"
1276};
1277
1278/* function to print kernel argument (used by DisasmAmd and DisasmAmdCL2 */
1279void CLRX::dumpAmdKernelArg(std::ostream& output, const AmdKernelArgInput& arg, bool cl20)
1280{
1281    size_t bufSize;
1282    char buf[100];
1283    output.write("        .arg ", 13);
1284    output.write(arg.argName.c_str(), arg.argName.size());
1285    output.write(", \"", 3);
1286    output.write(arg.typeName.c_str(), arg.typeName.size());
1287    if (arg.argType != KernelArgType::POINTER)
1288    {
1289        if (arg.argType > KernelArgType::MAX_VALUE_CL2)
1290            throw DisasmException("Unknown argument type");
1291        bufSize = snprintf(buf, 100, "\", %s",
1292                   kernelArgTypeNamesTbl[cxuint(arg.argType)]);
1293        output.write(buf, bufSize);
1294        if (arg.argType == KernelArgType::STRUCTURE)
1295        {
1296            // structure size
1297            bufSize = snprintf(buf, 100, ", %u", arg.structSize);
1298            output.write(buf, bufSize);
1299        }
1300        bool isImage = false;
1301        if (isKernelArgImage(arg.argType))
1302        {
1303            // images
1304            isImage = true;
1305            cxbyte access = arg.ptrAccess & KARG_PTR_ACCESS_MASK;
1306            // print access qualifier
1307            if (access == KARG_PTR_READ_ONLY)
1308                output.write(", read_only", 11);
1309            else if (access == KARG_PTR_WRITE_ONLY)
1310                output.write(", write_only", 12);
1311            else if (access == KARG_PTR_READ_WRITE)
1312                output.write(", read_write", 12);
1313            else
1314                output.write(", ", 2);
1315        }
1316        if (isImage || ((!cl20 && arg.argType == KernelArgType::COUNTER32) ||
1317            (cl20 && arg.argType == KernelArgType::SAMPLER)))
1318        {
1319            // print resource id: only for images counters and for samplers (if CL2.0)
1320            bufSize = snprintf(buf, 100, ", %u", arg.resId);
1321            output.write(buf, bufSize);
1322        }
1323    }
1324    else
1325    {
1326        if (arg.pointerType > KernelArgType::MAX_VALUE_CL2)
1327            throw DisasmException("Unknown argument pointer type");
1328        // pointer
1329        bufSize = snprintf(buf, 100, "\", %s*",
1330                   kernelArgTypeNamesTbl[cxuint(arg.pointerType)]);
1331        output.write(buf, bufSize);
1332        if (arg.pointerType == KernelArgType::STRUCTURE)
1333        {
1334            // structure size
1335            bufSize = snprintf(buf, 100, ", %u", arg.structSize);
1336            output.write(buf, bufSize);
1337        }
1338        // print pointer space
1339        if (arg.ptrSpace == KernelPtrSpace::CONSTANT)
1340            output.write(", constant", 10);
1341        else if (arg.ptrSpace == KernelPtrSpace::LOCAL)
1342            output.write(", local", 7);
1343        else if (arg.ptrSpace == KernelPtrSpace::GLOBAL)
1344            output.write(", global", 8);
1345       
1346        if ((arg.ptrAccess & (KARG_PTR_CONST|KARG_PTR_VOLATILE|KARG_PTR_RESTRICT))!=0)
1347        {
1348            // pointer access
1349            bufSize = snprintf(buf, 100, ",%s%s%s",
1350                     ((arg.ptrAccess & KARG_PTR_CONST) ? " const" : ""),
1351                     ((arg.ptrAccess & KARG_PTR_RESTRICT) ? " restrict" : ""),
1352                     ((arg.ptrAccess & KARG_PTR_VOLATILE) ? " volatile" : ""));
1353            output.write(buf, bufSize);
1354        }
1355        else // empty
1356            output.write(", ", 2);
1357        if (arg.ptrSpace==KernelPtrSpace::CONSTANT && !cl20)
1358        {
1359            // constant size
1360            bufSize = snprintf(buf, 100, ", %" PRIu64, uint64_t(arg.constSpaceSize));
1361            output.write(buf, bufSize);
1362        }
1363        if (arg.ptrSpace!=KernelPtrSpace::LOCAL && !cl20)
1364        {
1365            // resid
1366            bufSize = snprintf(buf, 100, ", %u", arg.resId);
1367            output.write(buf, bufSize);
1368        }
1369    }
1370    if (!arg.used)
1371        output.write(", unused\n", 9);
1372    // further flags for OpenCL 2.0 binary format
1373    else if (cl20 && arg.used==AMDCL2_ARGUSED_READ)
1374        output.write(", rdonly\n", 9);
1375    else if (cl20 && arg.used==AMDCL2_ARGUSED_WRITE)
1376        output.write(", wronly\n", 9);
1377    else
1378        output.write("\n", 1);
1379}
1380
1381static void dumpAmdKernelConfig(std::ostream& output, const AmdKernelConfig& config)
1382{
1383    size_t bufSize;
1384    char buf[100];
1385    output.write("    .config\n", 12);
1386    if (config.dimMask != BINGEN_DEFAULT)
1387    {
1388        // print dimensions (.dims xyz)
1389        strcpy(buf, "        .dims ");
1390        bufSize = 14;
1391        if ((config.dimMask & 1) != 0)
1392            buf[bufSize++] = 'x';
1393        if ((config.dimMask & 2) != 0)
1394            buf[bufSize++] = 'y';
1395        if ((config.dimMask & 4) != 0)
1396            buf[bufSize++] = 'z';
1397        if ((config.dimMask & 7) != ((config.dimMask>>3) & 7))
1398        {
1399            buf[bufSize++] = ',';
1400            buf[bufSize++] = ' ';
1401            if ((config.dimMask & 8) != 0)
1402                buf[bufSize++] = 'x';
1403            if ((config.dimMask & 16) != 0)
1404                buf[bufSize++] = 'y';
1405            if ((config.dimMask & 32) != 0)
1406                buf[bufSize++] = 'z';
1407        }
1408        buf[bufSize++] = '\n';
1409        output.write(buf, bufSize);
1410    }
1411    // print reqd_work_group_size: .cws XSIZE[,YSIZE[,ZSIZE]]
1412    if (config.reqdWorkGroupSize[0] != 0 || config.reqdWorkGroupSize[1] != 0 ||
1413        config.reqdWorkGroupSize[2] != 0)
1414    {
1415        bufSize = snprintf(buf, 100, "        .cws %u, %u, %u\n",
1416               config.reqdWorkGroupSize[0], config.reqdWorkGroupSize[1],
1417               config.reqdWorkGroupSize[2]);
1418        output.write(buf, bufSize);
1419    }
1420   
1421#if CLRX_VERSION_NUMBER >= CLRX_POLICY_UNIFIED_SGPR_COUNT
1422    bufSize = snprintf(buf, 100, "        .sgprsnum %u\n", config.usedSGPRsNum+2);
1423#else
1424    bufSize = snprintf(buf, 100, "        .sgprsnum %u\n", config.usedSGPRsNum);
1425#endif
1426    output.write(buf, bufSize);
1427    bufSize = snprintf(buf, 100, "        .vgprsnum %u\n", config.usedVGPRsNum);
1428    output.write(buf, bufSize);
1429    if (config.hwRegion!=0 && config.hwRegion!=BINGEN_DEFAULT)
1430    {
1431        bufSize = snprintf(buf, 100, "        .hwregion %u\n", config.hwRegion);
1432        output.write(buf, bufSize);
1433    }
1434    if (config.hwLocalSize!=0)
1435    {
1436        bufSize = snprintf(buf, 100, "        .hwlocal %" PRIu64 "\n",
1437                       uint64_t(config.hwLocalSize));
1438        output.write(buf, bufSize);
1439    }
1440    bufSize = snprintf(buf, 100, "        .floatmode 0x%02x\n", config.floatMode);
1441    output.write(buf, bufSize);
1442    if (config.scratchBufferSize!=0)
1443    {
1444        bufSize = snprintf(buf, 100, "        .scratchbuffer %u\n",
1445                           config.scratchBufferSize);
1446        output.write(buf, bufSize);
1447    }
1448    if (config.uavId!=BINGEN_DEFAULT)
1449    {
1450        bufSize = snprintf(buf, 100, "        .uavid %u\n", config.uavId);
1451        output.write(buf, bufSize);
1452    }
1453    if (config.uavPrivate!=BINGEN_DEFAULT)
1454    {
1455        bufSize = snprintf(buf, 100, "        .uavprivate %u\n", config.uavPrivate);
1456        output.write(buf, bufSize);
1457    }
1458    if (config.printfId!=BINGEN_DEFAULT)
1459    {
1460        bufSize = snprintf(buf, 100, "        .printfid %u\n", config.printfId);
1461        output.write(buf, bufSize);
1462    }
1463    if (config.privateId!=BINGEN_DEFAULT)
1464    {
1465        bufSize = snprintf(buf, 100, "        .privateid %u\n", config.privateId);
1466        output.write(buf, bufSize);
1467    }
1468    if (config.constBufferId!=BINGEN_DEFAULT)
1469    {
1470        bufSize = snprintf(buf, 100, "        .cbid %u\n", config.constBufferId);
1471        output.write(buf, bufSize);
1472    }
1473    bufSize = snprintf(buf, 100, "        .earlyexit %u\n", config.earlyExit);
1474    output.write(buf, bufSize);
1475    bufSize = snprintf(buf, 100, "        .condout %u\n", config.condOut);
1476    output.write(buf, bufSize);
1477    bufSize = snprintf(buf, 100, "        .pgmrsrc2 0x%08x\n", config.pgmRSRC2);
1478    output.write(buf, bufSize);
1479    // flags in PGMRSRC2
1480    if (config.ieeeMode)
1481        output.write("        .ieeemode\n", 18);
1482    if (config.tgSize)
1483        output.write("        .tgsize\n", 16);
1484    if (config.usePrintf)
1485        output.write("        .useprintf\n", 19);
1486    if (config.useConstantData)
1487        output.write("        .useconstdata\n", 22);
1488    if ((config.exceptions & 0x7f) != 0)
1489    {
1490        bufSize = snprintf(buf, 100, "        .exceptions 0x%02x\n",
1491                   cxuint(config.exceptions));
1492        output.write(buf, bufSize);
1493    }
1494    /* user datas */
1495    for (AmdUserData userData: config.userDatas)
1496    {
1497        const char* dataClassName = "unknown";
1498        if (userData.dataClass < sizeof(dataClassNameTbl)/sizeof(char*))
1499            dataClassName = dataClassNameTbl[userData.dataClass];
1500        bufSize = snprintf(buf, 100, "        .userdata %s, %u, %u, %u\n", dataClassName,
1501                userData.apiSlot, userData.regStart, userData.regSize);
1502        output.write(buf, bufSize);
1503    }
1504    // arguments
1505    for (const AmdKernelArgInput& arg: config.args)
1506        dumpAmdKernelArg(output, arg, false);
1507    // samplers
1508    for (cxuint sampler: config.samplers)
1509    {
1510        bufSize = snprintf(buf, 100, "        .sampler 0x%x\n", sampler);
1511        output.write(buf, bufSize);
1512    }
1513}
1514
1515void CLRX::disassembleAmd(std::ostream& output, const AmdDisasmInput* amdInput,
1516       ISADisassembler* isaDisassembler, size_t& sectionCount, Flags flags)
1517{
1518    if (amdInput->is64BitMode)
1519        output.write(".64bit\n", 7);
1520    else
1521        output.write(".32bit\n", 7);
1522   
1523    const bool doMetadata = ((flags & DISASM_METADATA) != 0);
1524    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
1525    const bool doDumpCode = ((flags & DISASM_DUMPCODE) != 0);
1526   
1527    if (doMetadata)
1528    {
1529        // compile options and driver info belongs to metadata
1530        output.write(".compile_options \"", 18);
1531        const std::string escapedCompileOptions = 
1532                escapeStringCStyle(amdInput->compileOptions);
1533        output.write(escapedCompileOptions.c_str(), escapedCompileOptions.size());
1534        output.write("\"\n.driver_info \"", 16);
1535        const std::string escapedDriverInfo =
1536                escapeStringCStyle(amdInput->driverInfo);
1537        output.write(escapedDriverInfo.c_str(), escapedDriverInfo.size());
1538        output.write("\"\n", 2);
1539    }
1540   
1541    if (doDumpData && amdInput->globalData != nullptr && amdInput->globalDataSize != 0)
1542    {   //
1543        output.write(".globaldata\n", 12);
1544        printDisasmData(amdInput->globalDataSize, amdInput->globalData, output);
1545    }
1546   
1547    for (const AmdDisasmKernelInput& kinput: amdInput->kernels)
1548    {
1549        output.write(".kernel ", 8);
1550        output.write(kinput.kernelName.c_str(), kinput.kernelName.size());
1551        output.put('\n');
1552        if ((flags & DISASM_CONFIG) == 0) // if not config
1553            dumpAmdKernelDatas(output, kinput, flags);
1554        else
1555        {
1556            // dump in human readable configuration
1557            AmdKernelConfig config = getAmdKernelConfig(kinput.metadataSize,
1558                    kinput.metadata, kinput.calNotes, amdInput->driverInfo,
1559                    kinput.header, getGPUArchitectureFromDeviceType(amdInput->deviceType));
1560            dumpAmdKernelConfig(output, config);
1561        }
1562       
1563        if (doDumpCode && kinput.code != nullptr && kinput.codeSize != 0)
1564        {
1565            // input kernel code (main disassembly)
1566            output.write("    .text\n", 10);
1567            isaDisassembler->setInput(kinput.codeSize, kinput.code);
1568            isaDisassembler->beforeDisassemble();
1569            isaDisassembler->disassemble();
1570            sectionCount++;
1571        }
1572    }
1573}
Note: See TracBrowser for help on using the repository browser.