source: CLRX/CLRadeonExtender/trunk/amdasm/DisasmAmdCL2.cpp @ 3575

Last change on this file since 3575 was 3575, checked in by matszpk, 2 years ago

CLRadeonExtender: Change Copyright dates.

File size: 38.6 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 <string>
23#include <inttypes.h>
24#include <ostream>
25#include <cstdio>
26#include <memory>
27#include <vector>
28#include <utility>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/utils/MemAccess.h>
31#include <CLRX/amdbin/AmdCL2Binaries.h>
32#include <CLRX/amdbin/AmdCL2BinGen.h>
33#include <CLRX/amdasm/Disassembler.h>
34#include <CLRX/utils/GPUId.h>
35#include "DisasmInternals.h"
36
37using namespace CLRX;
38
39struct CLRX_INTERNAL AmdCL2Types32: Elf32Types
40{
41    typedef AmdCL2MainGPUBinary32 AmdCL2MainBinary;
42    typedef AmdCL2GPUMetadataHeader32 MetadataHeader;
43    typedef AmdCL2GPUKernelArgEntry32 KernelArgEntry;
44};
45
46struct CLRX_INTERNAL AmdCL2Types64: Elf64Types
47{
48    typedef AmdCL2MainGPUBinary64 AmdCL2MainBinary;
49    typedef AmdCL2GPUMetadataHeader64 MetadataHeader;
50    typedef AmdCL2GPUKernelArgEntry64 KernelArgEntry;
51};
52
53// generate AMD CL2.0 disasm input from main binary
54template<typename AmdCL2Types>
55static AmdCL2DisasmInput* getAmdCL2DisasmInputFromBinary(
56            const typename AmdCL2Types::AmdCL2MainBinary& binary, cxuint driverVersion)
57{
58    std::unique_ptr<AmdCL2DisasmInput> input(new AmdCL2DisasmInput);
59    input->is64BitMode = (binary.getHeader().e_ident[EI_CLASS] == ELFCLASS64);
60   
61    input->deviceType = binary.determineGPUDeviceType(input->archMinor,
62                  input->archStepping, driverVersion);
63    if (driverVersion == 0)
64        input->driverVersion = binary.getDriverVersion();
65    else
66        input->driverVersion = driverVersion;
67   
68    input->compileOptions = binary.getCompileOptions();
69    input->aclVersionString = binary.getAclVersionString();
70    bool isInnerNewBinary = binary.hasInnerBinary() &&
71                binary.getDriverVersion()>=191205;
72   
73    input->samplerInitSize = 0;
74    input->samplerInit = nullptr;
75    input->globalDataSize = 0;
76    input->globalData = nullptr;
77    input->rwDataSize = 0;
78    input->rwData = nullptr;
79    input->bssAlignment = input->bssSize = 0;
80    std::vector<std::pair<size_t, size_t> > sortedRelocs; // by offset
81    const cxbyte* textPtr = nullptr;
82    const size_t kernelInfosNum = binary.getKernelInfosNum();
83   
84    // set section indices as undefined
85    uint16_t gDataSectionIdx = SHN_UNDEF;
86    uint16_t rwDataSectionIdx = SHN_UNDEF;
87    uint16_t bssDataSectionIdx = SHN_UNDEF;
88   
89    if (isInnerNewBinary)
90    {
91        const AmdCL2InnerGPUBinary& innerBin = binary.getInnerBinary();
92        input->globalDataSize = innerBin.getGlobalDataSize();
93        input->globalData = innerBin.getGlobalData();
94        input->rwDataSize = innerBin.getRwDataSize();
95        input->rwData = innerBin.getRwData();
96        input->samplerInitSize = innerBin.getSamplerInitSize();
97        input->samplerInit = innerBin.getSamplerInit();
98        input->bssAlignment = innerBin.getBssAlignment();
99        input->bssSize = innerBin.getBssSize();
100       
101        // if no kernels and data
102        if (kernelInfosNum==0)
103            return input.release();
104       
105        // get and sort relocations by offset
106        size_t relaNum = innerBin.getTextRelaEntriesNum();
107        for (size_t i = 0; i < relaNum; i++)
108        {
109            const Elf64_Rela& rel = innerBin.getTextRelaEntry(i);
110            sortedRelocs.push_back(std::make_pair(size_t(ULEV(rel.r_offset)), i));
111        }
112        // sort map
113        mapSort(sortedRelocs.begin(), sortedRelocs.end());
114        // get code section pointer for determine relocation position kernel code
115        textPtr = innerBin.getSectionContent(".hsatext");
116       
117        // getting optional sections in inner binary
118        try
119        { gDataSectionIdx = innerBin.getSectionIndex(".hsadata_readonly_agent"); }
120        catch(const Exception& ex)
121        { }
122        try
123        { rwDataSectionIdx = innerBin.getSectionIndex(".hsadata_global_agent"); }
124        catch(const Exception& ex)
125        { }
126        try
127        { bssDataSectionIdx = innerBin.getSectionIndex(".hsabss_global_agent"); }
128        catch(const Exception& ex)
129        { }
130        // relocations for global data section (sampler symbols)
131        relaNum = innerBin.getGlobalDataRelaEntriesNum();
132        // section index for samplerinit (will be used for comparing sampler symbol section
133        uint16_t samplerInitSecIndex = SHN_UNDEF;
134        try
135        { samplerInitSecIndex = innerBin.getSectionIndex(".hsaimage_samplerinit"); }
136        catch(const Exception& ex)
137        { }
138       
139        // store sampler relocations to samplerRelocs
140        for (size_t i = 0; i < relaNum; i++)
141        {
142            const Elf64_Rela& rel = innerBin.getGlobalDataRelaEntry(i);
143            size_t symIndex = ELF64_R_SYM(ULEV(rel.r_info));
144            const Elf64_Sym& sym = innerBin.getSymbol(symIndex);
145            // check symbol type, section and value
146            if (ELF64_ST_TYPE(sym.st_info) != 12)
147                throw DisasmException("Wrong sampler symbol");
148            uint64_t value = ULEV(sym.st_value);
149            if (ULEV(sym.st_shndx) != samplerInitSecIndex)
150                throw DisasmException("Wrong section for sampler symbol");
151            if ((value&7) != 0)
152                throw DisasmException("Wrong value of sampler symbol");
153            input->samplerRelocs.push_back({ size_t(ULEV(rel.r_offset)),
154                size_t(value>>3) });
155        }
156    }
157    else if (kernelInfosNum==0)
158        return input.release();
159   
160    input->kernels.resize(kernelInfosNum);
161    auto sortedRelocIter = sortedRelocs.begin();
162   
163    // preparing kernel inputs
164    for (cxuint i = 0; i < kernelInfosNum; i++)
165    {
166        const KernelInfo& kernelInfo = binary.getKernelInfo(i);
167        AmdCL2DisasmKernelInput& kinput = input->kernels[i];
168        kinput.kernelName = kernelInfo.kernelName;
169        kinput.metadataSize = binary.getMetadataSize(i);
170        kinput.metadata = binary.getMetadata(i);
171       
172        kinput.isaMetadataSize = 0;
173        kinput.isaMetadata = nullptr;
174        // setup isa metadata content
175        const AmdCL2GPUKernelMetadata* isaMetadata = nullptr;
176        if (i < binary.getISAMetadatasNum())
177            isaMetadata = &binary.getISAMetadataEntry(i);
178        if (isaMetadata == nullptr || isaMetadata->kernelName != kernelInfo.kernelName)
179        {
180            // fallback if not in order
181            try
182            { isaMetadata = &binary.getISAMetadataEntry(
183                            kernelInfo.kernelName.c_str()); }
184            catch(const Exception& ex) // failed
185            { isaMetadata = nullptr; }
186        }
187        if (isaMetadata!=nullptr)
188        {
189            kinput.isaMetadataSize = isaMetadata->size;
190            kinput.isaMetadata = isaMetadata->data;
191        }
192       
193        kinput.code = nullptr;
194        kinput.codeSize = 0;
195        kinput.setup = nullptr;
196        kinput.setupSize = 0;
197        kinput.stub = nullptr;
198        kinput.stubSize = 0;
199        if (!binary.hasInnerBinary())
200            continue; // nothing else to set
201       
202        // get kernel code, setup and stub content
203        const AmdCL2InnerGPUBinaryBase& innerBin = binary.getInnerBinaryBase();
204        const AmdCL2GPUKernel* kernelData = nullptr;
205        if (i < innerBin.getKernelsNum())
206            kernelData = &innerBin.getKernelData(i);
207        if (kernelData==nullptr || kernelData->kernelName != kernelInfo.kernelName)
208            kernelData = &innerBin.getKernelData(kernelInfo.kernelName.c_str());
209       
210        if (kernelData!=nullptr)
211        {
212            // if set kernel code and kernel setup (AMD HSA config)
213            kinput.code = kernelData->code;
214            kinput.codeSize = kernelData->codeSize;
215            kinput.setup = kernelData->setup;
216            kinput.setupSize = kernelData->setupSize;
217        }
218        if (!isInnerNewBinary)
219        {
220            // old drivers
221            const AmdCL2OldInnerGPUBinary& oldInnerBin = binary.getOldInnerBinary();
222            const AmdCL2GPUKernelStub* kstub = nullptr;
223            if (i < innerBin.getKernelsNum())
224                kstub = &oldInnerBin.getKernelStub(i);
225            if (kstub==nullptr || kernelData->kernelName != kernelInfo.kernelName)
226                kstub = &oldInnerBin.getKernelStub(kernelInfo.kernelName.c_str());
227            if (kstub!=nullptr)
228            {
229                kinput.stubSize = kstub->size;
230                kinput.stub = kstub->data;
231            }
232        }
233        else
234        {
235            // relocations
236            const AmdCL2InnerGPUBinary& innerBin = binary.getInnerBinary();
237           
238            if (sortedRelocIter != sortedRelocs.end() &&
239                    sortedRelocIter->first < size_t(kinput.code-textPtr))
240                throw DisasmException("Code relocation offset outside kernel code");
241           
242            if (sortedRelocIter != sortedRelocs.end())
243            {
244                size_t end = kinput.code+kinput.codeSize-textPtr;
245                for (; sortedRelocIter != sortedRelocs.end() &&
246                    sortedRelocIter->first<=end; ++sortedRelocIter)
247                {
248                    // add relocations
249                    const Elf64_Rela& rela = innerBin.getTextRelaEntry(
250                                sortedRelocIter->second);
251                    uint32_t symIndex = ELF64_R_SYM(ULEV(rela.r_info));
252                    int64_t addend = ULEV(rela.r_addend);
253                    cxuint rsym = 0;
254                    // check this symbol
255                    const Elf64_Sym& sym = innerBin.getSymbol(symIndex);
256                    uint16_t symShndx = ULEV(sym.st_shndx);
257                    if (symShndx!=gDataSectionIdx && symShndx!=rwDataSectionIdx &&
258                        symShndx!=bssDataSectionIdx)
259                        throw DisasmException("Symbol is not placed in global or "
260                                "rwdata data or bss is illegal");
261                    addend += ULEV(sym.st_value);
262                    rsym = (symShndx==rwDataSectionIdx) ? 1 : 
263                        ((symShndx==bssDataSectionIdx) ? 2 : 0);
264                    // determine relocation type
265                    RelocType relocType;
266                    uint32_t rtype = ELF64_R_TYPE(ULEV(rela.r_info));
267                    if (rtype==1)
268                        relocType = RELTYPE_LOW_32BIT;
269                    else if (rtype==2)
270                        relocType = RELTYPE_HIGH_32BIT;
271                    else
272                        throw DisasmException("Unknown relocation type");
273                    // put text relocs. compute offset by subtracting current code offset
274                    kinput.textRelocs.push_back(AmdCL2RelaEntry{sortedRelocIter->first-
275                        (kinput.code-textPtr), relocType, rsym, addend });
276                }
277            }
278        }
279    }
280    if (sortedRelocIter != sortedRelocs.end())
281        throw DisasmException("Code relocation offset outside kernel code");
282    return input.release();
283}
284
285// get AMD CL2 input from 32-bit binary
286AmdCL2DisasmInput* CLRX::getAmdCL2DisasmInputFromBinary32(
287                const AmdCL2MainGPUBinary32& binary, cxuint driverVersion)
288{
289    return getAmdCL2DisasmInputFromBinary<AmdCL2Types32>(binary, driverVersion);
290}
291
292// get AMD CL2 input from 64-bit binary
293AmdCL2DisasmInput* CLRX::getAmdCL2DisasmInputFromBinary64(
294                const AmdCL2MainGPUBinary64& binary, cxuint driverVersion)
295{
296    return getAmdCL2DisasmInputFromBinary<AmdCL2Types64>(binary, driverVersion);
297}
298
299// internal AMD OpenCL 2.0 Kernel setup (part of AMD HSA config)
300struct CLRX_INTERNAL IntAmdCL2SetupData
301{
302    uint32_t pgmRSRC1;
303    uint32_t pgmRSRC2;
304    uint16_t setup1;
305    uint16_t archInd;
306    uint32_t scratchBufferSize;
307    uint32_t localSize; // in bytes
308    uint32_t gdsSize;   // in bytes
309    uint32_t kernelArgsSize;
310    uint32_t zeroes[2];
311    // really is, reserved Xgprs, but filled by driver
312    uint16_t sgprsNumAll;
313    uint16_t vgprsNum16;
314    uint32_t vgprsNum;
315    uint32_t sgprsNum;
316    uint32_t zero3;
317    uint32_t version; // ??
318};
319
320static const size_t disasmArgTypeNameMapSize = sizeof(disasmArgTypeNameMap)/
321            sizeof(std::pair<const char*, KernelArgType>);
322
323// table of argument vector type
324static const KernelArgType cl20ArgTypeVectorTable[] =
325{
326    KernelArgType::CHAR,
327    KernelArgType::CHAR2,
328    KernelArgType::CHAR3,
329    KernelArgType::CHAR4,
330    KernelArgType::CHAR8,
331    KernelArgType::CHAR16,
332    KernelArgType::SHORT,
333    KernelArgType::SHORT2,
334    KernelArgType::SHORT3,
335    KernelArgType::SHORT4,
336    KernelArgType::SHORT8,
337    KernelArgType::SHORT16,
338    KernelArgType::INT,
339    KernelArgType::INT2,
340    KernelArgType::INT3,
341    KernelArgType::INT4,
342    KernelArgType::INT8,
343    KernelArgType::INT16,
344    KernelArgType::LONG,
345    KernelArgType::LONG2,
346    KernelArgType::LONG3,
347    KernelArgType::LONG4,
348    KernelArgType::LONG8,
349    KernelArgType::LONG16,
350    KernelArgType::VOID,
351    KernelArgType::VOID,
352    KernelArgType::VOID,
353    KernelArgType::VOID,
354    KernelArgType::VOID,
355    KernelArgType::VOID,
356    KernelArgType::FLOAT,
357    KernelArgType::FLOAT2,
358    KernelArgType::FLOAT3,
359    KernelArgType::FLOAT4,
360    KernelArgType::FLOAT8,
361    KernelArgType::FLOAT16,
362    KernelArgType::DOUBLE,
363    KernelArgType::DOUBLE2,
364    KernelArgType::DOUBLE3,
365    KernelArgType::DOUBLE4,
366    KernelArgType::DOUBLE8,
367    KernelArgType::DOUBLE16
368};
369
370static const cxuint vectorIdTable[17] =
371{ UINT_MAX, 0, 1, 2, 3, UINT_MAX, UINT_MAX, UINT_MAX, 4,
372  UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, 5 };
373
374template<typename Types>
375static AmdCL2KernelConfig genKernelConfig(size_t metadataSize, const cxbyte* metadata,
376        size_t setupSize, const cxbyte* setup, const std::vector<size_t> samplerOffsets,
377        const std::vector<AmdCL2RelaEntry>& textRelocs, bool isGCN14)
378{
379    AmdCL2KernelConfig config{};
380    const typename Types::MetadataHeader* mdHdr =
381            reinterpret_cast<const typename Types::MetadataHeader*>(metadata);
382    size_t headerSize = ULEV(mdHdr->size);
383    // get CWS (reqd_work_group_size)
384    for (size_t i = 0; i < 3; i++)
385        config.reqdWorkGroupSize[i] = ULEV(mdHdr->reqdWorkGroupSize[i]);
386   
387    if (setup != nullptr)
388    {
389        // if passed to this function
390        const IntAmdCL2SetupData* setupData =
391                reinterpret_cast<const IntAmdCL2SetupData*>(setup + 48);
392        uint32_t pgmRSRC1 = ULEV(setupData->pgmRSRC1);
393        uint32_t pgmRSRC2 = ULEV(setupData->pgmRSRC2);
394        /* initializing fields from PGM_RSRC1 and PGM_RSRC2 */
395        config.dimMask = (pgmRSRC2>>7)&7;
396        config.ieeeMode = (pgmRSRC1>>23)&1;
397        config.exceptions = (pgmRSRC2>>24)&0xff;
398        config.floatMode = (pgmRSRC1>>12)&0xff;
399        config.priority = (pgmRSRC1>>10)&3;
400        config.tgSize = (pgmRSRC2>>10)&1;
401        config.privilegedMode = (pgmRSRC1>>20)&1;
402        config.dx10Clamp = (pgmRSRC1>>21)&1;
403        config.debugMode = (pgmRSRC1>>22)&1;
404        config.pgmRSRC2 = pgmRSRC2;
405        config.pgmRSRC1 = pgmRSRC1;
406        config.usedVGPRsNum = ULEV(setupData->vgprsNum);
407        config.usedSGPRsNum = ULEV(setupData->sgprsNum);
408        config.scratchBufferSize = ULEV(setupData->scratchBufferSize);
409        config.localSize = ULEV(setupData->localSize);
410        config.gdsSize = ULEV(setupData->gdsSize);
411        uint16_t ksetup1 = ULEV(setupData->setup1);
412        config.useSetup = (ksetup1&2)!=0;
413        config.useArgs = (ksetup1&8)!=0;
414        config.useGeneric = config.useEnqueue = false;
415        if (ksetup1==0x2f) // if generic pointer support
416            config.useGeneric = true;
417        else if (!isGCN14)
418            config.useEnqueue = (ksetup1&0x20)!=0;
419        else // for GFX9 - check number of all registers must be 6+
420            config.useEnqueue = (setupData->sgprsNum+6 == setupData->sgprsNumAll);
421    }
422   
423    // get samplers
424    for (const AmdCL2RelaEntry& reloc: textRelocs)
425    {
426        // check if sampler
427        auto it = std::find(samplerOffsets.begin(), samplerOffsets.end(), reloc.addend);
428        if (it!=samplerOffsets.end())
429            config.samplers.push_back(it-samplerOffsets.begin());
430    }
431    std::sort(config.samplers.begin(), config.samplers.end());
432    config.samplers.resize(std::unique(config.samplers.begin(), config.samplers.end()) -
433                config.samplers.begin());
434    // get kernel args
435    size_t argOffset = headerSize + ULEV(mdHdr->firstNameLength) + 
436            ULEV(mdHdr->secondNameLength)+2;
437    if (ULEV(*(const uint32_t*)(metadata+argOffset)) ==
438                (sizeof(typename Types::KernelArgEntry)<<8))
439        argOffset++;    // fix for AMD GPUPRO driver (2036.03) */
440    const typename Types::KernelArgEntry* argPtr = reinterpret_cast<
441            const typename Types::KernelArgEntry*>(metadata + argOffset);
442    const uint32_t argsNum = ULEV(mdHdr->argsNum);
443    const char* strBase = (const char*)metadata;
444    size_t strOffset = argOffset + sizeof(typename Types::KernelArgEntry)*(argsNum+1);
445   
446    // get argument type from metadata
447    for (uint32_t i = 0; i < argsNum; i++, argPtr++)
448    {
449        AmdKernelArgInput arg{};
450        size_t nameSize = ULEV(argPtr->argNameSize);
451        arg.argName.assign(strBase+strOffset, nameSize);
452        strOffset += nameSize+1;
453        nameSize = ULEV(argPtr->typeNameSize);
454        arg.typeName.assign(strBase+strOffset, nameSize);
455        strOffset += nameSize+1;
456       
457        uint32_t vectorSize = ULEV(argPtr->vectorLength);
458        uint32_t argType = ULEV(argPtr->argType);
459        uint32_t kindOfType = ULEV(argPtr->kindOfType);
460       
461        arg.ptrSpace = KernelPtrSpace::NONE;
462        arg.ptrAccess = KARG_PTR_NORMAL;
463        arg.argType = KernelArgType::VOID;
464       
465        if (ULEV(argPtr->isConst))
466            arg.ptrAccess |= KARG_PTR_CONST;
467        arg.used = AMDCL2_ARGUSED_READ_WRITE; // default is used
468       
469        if (!ULEV(argPtr->isPointerOrPipe))
470        {
471            // if not point or pipe (get regular type: scalar, image, sampler,...)
472            switch(argType)
473            {
474                case 0:
475                    if (kindOfType!=1) // not sampler
476                        throw DisasmException("Wrong kernel argument type");
477                    arg.argType = KernelArgType::SAMPLER;
478                    break;
479                case 1:  // read_only image
480                case 2:  // write_only image
481                case 3:  // read_write image
482                    if (kindOfType==2) // not image
483                    {
484                        arg.argType = KernelArgType::IMAGE;
485                        arg.ptrAccess = (argType==1) ? KARG_PTR_READ_ONLY : (argType==2) ?
486                                 KARG_PTR_WRITE_ONLY : KARG_PTR_READ_WRITE;
487                        arg.ptrSpace = KernelPtrSpace::GLOBAL;
488                    }
489                    else if (argType==2 || argType == 3)
490                    {
491                        if (kindOfType!=4) // not scalar
492                            throw DisasmException("Wrong kernel argument type");
493                        arg.argType = (argType==3) ?
494                            KernelArgType::SHORT : KernelArgType::CHAR;
495                    }
496                    else
497                        throw DisasmException("Wrong kernel argument type");
498                    break;
499                case 4: // int
500                case 5: // long
501                    if (kindOfType!=4) // not scalar
502                        throw DisasmException("Wrong kernel argument type");
503                    arg.argType = (argType==5) ?
504                        KernelArgType::LONG : KernelArgType::INT;
505                    break;
506                case 6: // char
507                case 7: // short
508                case 8: // int
509                case 9: // long
510                case 11: // float
511                case 12: // double
512                {
513                    if (kindOfType!=4) // not scalar
514                        throw DisasmException("Wrong kernel argument type");
515                    const cxuint vectorId = vectorIdTable[vectorSize];
516                    if (vectorId == UINT_MAX)
517                        throw DisasmException("Wrong vector size");
518                    arg.argType = cl20ArgTypeVectorTable[(argType-6)*6 + vectorId];
519                    break;
520                }
521                case 15:
522                    if (kindOfType!=4) // not scalar
523                        throw DisasmException("Wrong kernel argument type");
524                    arg.argType = KernelArgType::STRUCTURE;
525                    break;
526                case 18:
527                    if (kindOfType!=7) // not scalar
528                        throw DisasmException("Wrong kernel argument type");
529                    arg.argType = KernelArgType::CMDQUEUE;
530                    break;
531                default:
532                    throw DisasmException("Wrong kernel argument type");
533                    break;
534            }
535           
536            auto it = binaryMapFind(disasmArgTypeNameMap,
537                        disasmArgTypeNameMap + disasmArgTypeNameMapSize,
538                        arg.typeName.c_str(), CStringLess());
539            if (it != disasmArgTypeNameMap + disasmArgTypeNameMapSize) // if found
540                arg.argType = it->second;
541           
542            if (arg.argType == KernelArgType::STRUCTURE)
543                arg.structSize = ULEV(argPtr->structSize);
544            else if (isKernelArgImage(arg.argType) || arg.argType==KernelArgType::SAMPLER)
545                arg.resId = LEV(argPtr->resId); // sampler and images have resource id
546        }
547        else
548        {
549            // pointer or pipe
550            if (argPtr->isPipe)
551                arg.used = (ULEV(argPtr->isPointerOrPipe))==3;
552            else
553                arg.used = (ULEV(argPtr->isPointerOrPipe));
554            uint32_t ptrType = ULEV(argPtr->ptrType);
555            uint32_t ptrSpace = ULEV(argPtr->ptrSpace);
556            if (argType == 7) // pointer or pipe
557                arg.argType = (argPtr->isPipe==0) ? KernelArgType::POINTER :
558                    KernelArgType::PIPE;
559            else if (argType == 15)
560                arg.argType = KernelArgType::POINTER;
561            if (arg.argType == KernelArgType::POINTER)
562            {
563                // if pointer
564                if (ptrSpace==3)
565                    arg.ptrSpace = KernelPtrSpace::LOCAL;
566                else if (ptrSpace==4)
567                    arg.ptrSpace = KernelPtrSpace::GLOBAL;
568                else if (ptrSpace==5)
569                    arg.ptrSpace = KernelPtrSpace::CONSTANT;
570                else
571                    throw DisasmException("Illegal pointer space");
572                // set access qualifiers (volatile, restrict, const)
573                arg.ptrAccess |= KARG_PTR_NORMAL;
574                if (argPtr->isRestrict)
575                    arg.ptrAccess |= KARG_PTR_RESTRICT;
576                if (argPtr->isVolatile)
577                    arg.ptrAccess |= KARG_PTR_VOLATILE;
578            }
579            else
580            {
581                // pointer space for pipe
582                if (ptrSpace!=4)
583                    throw DisasmException("Illegal pipe space");
584                arg.ptrSpace = KernelPtrSpace::GLOBAL;
585            }
586           
587            if (arg.argType == KernelArgType::POINTER)
588            {
589                // argument is pointer
590                size_t ptrTypeNameSize=0;
591                if (arg.typeName.empty())
592                {
593                    // ctx_struct_fld1
594                    if (ptrType >= 6 && ptrType <= 12)
595                        arg.pointerType = cl20ArgTypeVectorTable[(ptrType-6)*6];
596                    else
597                        arg.pointerType = KernelArgType::FLOAT;
598                }
599                else
600                {
601                    arg.pointerType = KernelArgType::VOID;
602                    switch (ptrType)
603                    {
604                        case 6: // char
605                        case 7: // short
606                        case 8: // int
607                        case 9: // long
608                        case 11: // float
609                        case 12: // double
610                            arg.pointerType = cl20ArgTypeVectorTable[(ptrType-6)*6];
611                            break;
612                    }
613                   
614                    while (isAlnum(arg.typeName[ptrTypeNameSize]) ||
615                        arg.typeName[ptrTypeNameSize]=='_') ptrTypeNameSize++;
616                    CString ptrTypeName(arg.typeName.c_str(), ptrTypeNameSize);
617                    if (arg.typeName.find('*')!=CString::npos) // assume 'void*'
618                    {
619                        auto it = binaryMapFind(disasmArgTypeNameMap,
620                                    disasmArgTypeNameMap + disasmArgTypeNameMapSize,
621                                    ptrTypeName.c_str(), CStringLess());
622                        if (it != disasmArgTypeNameMap + disasmArgTypeNameMapSize)
623                            // if found
624                            arg.pointerType = it->second;
625                        else if (arg.pointerType==KernelArgType::VOID)
626                            arg.pointerType = KernelArgType::STRUCTURE;
627                    }
628                    else if (ptrType==18)
629                    {
630                        /* if clkevent */
631                        arg.argType = KernelArgType::CLKEVENT;
632                        arg.pointerType = KernelArgType::VOID;
633                    }
634                    else /* unknown type of pointer */
635                        arg.pointerType = KernelArgType::VOID;
636                   
637                    // if structure
638                    if (arg.pointerType == KernelArgType::STRUCTURE)
639                        arg.structSize = ULEV(argPtr->ptrAlignment);
640                }
641            }
642        }
643        config.args.push_back(arg);
644    }
645    return config;
646}
647
648static void dumpAmdCL2KernelConfig(std::ostream& output,
649                    const AmdCL2KernelConfig& config, bool hsaConfig)
650{
651    size_t bufSize;
652    char buf[100];
653    if (hsaConfig)
654        output.write("    .hsaconfig\n", 15);
655    else
656        output.write("    .config\n", 12);
657   
658    if (!hsaConfig)
659    {
660        // do not print old-config style params if HSA config enabled
661        if (config.dimMask != BINGEN_DEFAULT)
662        {
663            strcpy(buf, "        .dims ");
664            bufSize = 14;
665            if ((config.dimMask & 1) != 0)
666                buf[bufSize++] = 'x';
667            if ((config.dimMask & 2) != 0)
668                buf[bufSize++] = 'y';
669            if ((config.dimMask & 4) != 0)
670                buf[bufSize++] = 'z';
671            buf[bufSize++] = '\n';
672            output.write(buf, bufSize);
673        }
674    }
675    bufSize = 0;
676    // print reqd_work_group_size: .cws XSIZE[,YSIZE[,ZSIZE]]
677    if (config.reqdWorkGroupSize[2] != 0)
678        bufSize = snprintf(buf, 100, "        .cws %u, %u, %u\n",
679               config.reqdWorkGroupSize[0], config.reqdWorkGroupSize[1],
680               config.reqdWorkGroupSize[2]);
681    else if (config.reqdWorkGroupSize[1] != 0)
682        bufSize = snprintf(buf, 100, "        .cws %u, %u\n", config.reqdWorkGroupSize[0],
683                   config.reqdWorkGroupSize[1]);
684    else if (config.reqdWorkGroupSize[0] != 0)
685        bufSize = snprintf(buf, 100, "        .cws %u\n", config.reqdWorkGroupSize[0]);
686    if (bufSize != 0) // if we have cws
687        output.write(buf, bufSize);
688   
689    if (!hsaConfig)
690    {
691        // do not print old-config style params if HSA config enabled
692        bufSize = snprintf(buf, 100, "        .sgprsnum %u\n", config.usedSGPRsNum);
693        output.write(buf, bufSize);
694        bufSize = snprintf(buf, 100, "        .vgprsnum %u\n", config.usedVGPRsNum);
695        output.write(buf, bufSize);
696       
697        if (config.localSize!=0)
698        {
699            bufSize = snprintf(buf, 100, "        .localsize %" PRIu64 "\n",
700                        uint64_t(config.localSize));
701            output.write(buf, bufSize);
702        }
703        if (config.gdsSize!=0)
704        {
705            bufSize = snprintf(buf, 100, "        .gdssize %u\n", config.gdsSize);
706            output.write(buf, bufSize);
707        }
708        bufSize = snprintf(buf, 100, "        .floatmode 0x%02x\n", config.floatMode);
709        output.write(buf, bufSize);
710        if (config.scratchBufferSize!=0)
711        {
712            bufSize = snprintf(buf, 100, "        .scratchbuffer %u\n",
713                            config.scratchBufferSize);
714            output.write(buf, bufSize);
715        }
716        bufSize = snprintf(buf, 100, "        .pgmrsrc1 0x%08x\n", config.pgmRSRC1);
717        output.write(buf, bufSize);
718        bufSize = snprintf(buf, 100, "        .pgmrsrc2 0x%08x\n", config.pgmRSRC2);
719        output.write(buf, bufSize);
720        // pgmrsrc1 and pgmrsrc2 flags
721        if (config.privilegedMode)
722            output.write("        .privmode\n", 18);
723        if (config.debugMode)
724            output.write("        .debugmode\n", 19);
725        if (config.dx10Clamp)
726            output.write("        .dx10clamp\n", 19);
727        if (config.ieeeMode)
728            output.write("        .ieeemode\n", 18);
729        if (config.tgSize)
730            output.write("        .tgsize\n", 16);
731        if ((config.exceptions & 0x7f) != 0)
732        {
733            bufSize = snprintf(buf, 100, "        .exceptions 0x%02x\n",
734                    cxuint(config.exceptions));
735            output.write(buf, bufSize);
736        }
737        if (config.useArgs)
738            output.write("        .useargs\n", 17);
739        if (config.useSetup)
740            output.write("        .usesetup\n", 18);
741        if (config.useEnqueue)
742            output.write("        .useenqueue\n", 20);
743        if (config.useGeneric)
744            output.write("        .usegeneric\n", 20);
745        bufSize = snprintf(buf, 100, "        .priority %u\n", config.priority);
746        output.write(buf, bufSize);
747    }
748}
749
750static void dumpAmdCL2ArgsAndSamplers(std::ostream& output,
751                    const AmdCL2KernelConfig& config)
752{
753    size_t bufSize;
754    char buf[100];
755    // arguments
756    for (const AmdKernelArgInput& arg: config.args)
757        dumpAmdKernelArg(output, arg, true);
758    // samplers
759    for (cxuint sampler: config.samplers)
760    {
761        bufSize = snprintf(buf, 100, "        .sampler %u\n", sampler);
762        output.write(buf, bufSize);
763    }
764}
765
766void CLRX::disassembleAmdCL2(std::ostream& output, const AmdCL2DisasmInput* amdCL2Input,
767       ISADisassembler* isaDisassembler, size_t& sectionCount, Flags flags)
768{
769    const bool doMetadata = ((flags & DISASM_METADATA) != 0);
770    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
771    const bool doDumpCode = ((flags & DISASM_DUMPCODE) != 0);
772    const bool doDumpConfig = ((flags & DISASM_CONFIG) != 0);
773    const bool doSetup = ((flags & DISASM_SETUP) != 0);
774    const bool doHSAConfig = ((flags & DISASM_HSACONFIG) != 0);
775   
776    if (amdCL2Input->is64BitMode)
777        output.write(".64bit\n", 7);
778    else
779        output.write(".32bit\n", 7);
780   
781    {
782        // print architecture version
783        char buf[40];
784        size_t size = snprintf(buf, 40, ".arch_minor %u\n", amdCL2Input->archMinor);
785        output.write(buf, size);
786        size = snprintf(buf, 40, ".arch_stepping %u\n", amdCL2Input->archStepping);
787        output.write(buf, size);
788        size = snprintf(buf, 40, ".driver_version %u\n",
789                   amdCL2Input->driverVersion);
790        output.write(buf, size);
791    }
792   
793    if (doMetadata)
794    {
795        // print compile options and acl_version
796        output.write(".compile_options \"", 18);
797        const std::string escapedCompileOptions = 
798                escapeStringCStyle(amdCL2Input->compileOptions);
799        output.write(escapedCompileOptions.c_str(), escapedCompileOptions.size());
800        output.write("\"\n.acl_version \"", 16);
801        const std::string escapedAclVersionString =
802                escapeStringCStyle(amdCL2Input->aclVersionString);
803        output.write(escapedAclVersionString.c_str(), escapedAclVersionString.size());
804        output.write("\"\n", 2);
805    }
806    if (doSetup && !doDumpConfig)
807    {
808        if (amdCL2Input->samplerInit!=nullptr && amdCL2Input->samplerInitSize!=0)
809        {
810            /// sampler init entries
811            output.write(".samplerinit\n", 13);
812            printDisasmData(amdCL2Input->samplerInitSize,
813                            amdCL2Input->samplerInit, output);
814        }
815    }
816    else if (doDumpConfig && amdCL2Input->samplerInit!=nullptr)
817    {
818        // print sampler values instead raw samler data in .samplerinit
819        char buf[50];
820        const size_t samplersNum = amdCL2Input->samplerInitSize>>3;
821        for (size_t i = 0; i < samplersNum; i++)
822        {
823            size_t bufSize = snprintf(buf, 50, ".sampler 0x%08x\n",
824                      ULEV(((const uint32_t*)amdCL2Input->samplerInit)[i*2+1]));
825            output.write(buf, bufSize);
826        }
827    }
828   
829    if (doDumpData && amdCL2Input->globalData != nullptr &&
830        amdCL2Input->globalDataSize != 0)
831    {
832        output.write(".globaldata\n", 12);
833        output.write(".gdata:\n", 8); /// symbol used by text relocations
834        printDisasmData(amdCL2Input->globalDataSize, amdCL2Input->globalData, output);
835        /// put sampler relocations at global data section
836        for (auto v: amdCL2Input->samplerRelocs)
837        {
838            output.write("    .samplerreloc ", 18);
839            char buf[64];
840            size_t bufPos = itocstrCStyle<size_t>(v.first, buf, 22);
841            buf[bufPos++] = ',';
842            buf[bufPos++] = ' ';
843            bufPos += itocstrCStyle<size_t>(v.second, buf+bufPos, 22);
844            buf[bufPos++] = '\n';
845            output.write(buf, bufPos);
846        }
847    }
848    if (doDumpData && amdCL2Input->rwData != nullptr &&
849        amdCL2Input->rwDataSize != 0)
850    {
851        output.write(".data\n", 6);
852        output.write(".ddata:\n", 8); /// symbol used by text relocations
853        printDisasmData(amdCL2Input->rwDataSize, amdCL2Input->rwData, output);
854    }
855   
856    if (doDumpData && amdCL2Input->bssSize)
857    {
858        // print .bss with alignment and skip (content filling)
859        output.write(".section .bss align=", 20);
860        char buf[64];
861        size_t bufPos = itocstrCStyle<size_t>(amdCL2Input->bssAlignment, buf, 22);
862        buf[bufPos++] = '\n';
863        output.write(buf, bufPos);
864        output.write(".bdata:\n", 8); /// symbol used by text relocations
865        output.write("    .skip ", 10);
866        bufPos = itocstrCStyle<size_t>(amdCL2Input->bssSize, buf, 22);
867        buf[bufPos++] = '\n';
868        output.write(buf, bufPos);
869    }
870   
871    // prepare sampler offsets
872    std::vector<size_t> samplerOffsets;
873    if (doDumpConfig)
874    {
875        for (auto reloc: amdCL2Input->samplerRelocs)
876        {
877            if (samplerOffsets.size() >= reloc.second)
878                samplerOffsets.resize(reloc.second+1);
879            samplerOffsets[reloc.second] = reloc.first;
880        }
881    }
882   
883    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(amdCL2Input->deviceType);
884    const cxuint maxSgprsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
885   
886    for (const AmdCL2DisasmKernelInput& kinput: amdCL2Input->kernels)
887    {
888        output.write(".kernel ", 8);
889        output.write(kinput.kernelName.c_str(), kinput.kernelName.size());
890        output.put('\n');
891        if (doMetadata && !doDumpConfig)
892        {
893            if (kinput.metadata != nullptr && kinput.metadataSize != 0)
894            {
895                // if kernel metadata available
896                output.write("    .metadata\n", 14);
897                printDisasmData(kinput.metadataSize, kinput.metadata, output, true);
898            }
899            if (kinput.isaMetadata != nullptr && kinput.isaMetadataSize != 0)
900            {
901                // if kernel isametadata available
902                output.write("    .isametadata\n", 17);
903                printDisasmData(kinput.isaMetadataSize, kinput.isaMetadata, output, true);
904            }
905        }
906        if (doSetup && !doDumpConfig)
907        {
908            if (kinput.stub != nullptr && kinput.stubSize != 0)
909            {
910                // if kernel setup available
911                output.write("    .stub\n", 10);
912                printDisasmData(kinput.stubSize, kinput.stub, output, true);
913            }
914            if (kinput.setup != nullptr && kinput.setupSize != 0)
915            {
916                // if kernel setup available
917                output.write("    .setup\n", 11);
918                printDisasmData(kinput.setupSize, kinput.setup, output, true);
919            }
920        }
921       
922        if (doDumpConfig)
923        {
924            const bool isGCN14 = getGPUArchitectureFromDeviceType(
925                        amdCL2Input->deviceType) >= GPUArchitecture::GCN1_4;
926            AmdCL2KernelConfig config{};
927            // get kernel config
928            if (amdCL2Input->is64BitMode)
929                config = genKernelConfig<AmdCL2Types64>(kinput.metadataSize,
930                        kinput.metadata, kinput.setupSize,
931                        (doHSAConfig ? nullptr : kinput.setup), samplerOffsets,
932                        kinput.textRelocs, isGCN14);
933            else
934                config = genKernelConfig<AmdCL2Types32>(kinput.metadataSize,
935                        kinput.metadata, kinput.setupSize,
936                        (doHSAConfig ? nullptr : kinput.setup), samplerOffsets,
937                        kinput.textRelocs, isGCN14);
938           
939            dumpAmdCL2KernelConfig(output, config, doHSAConfig);
940            if (doHSAConfig)
941            {
942                // print as HSA config
943                dumpAMDHSAConfig(output, maxSgprsNum, arch,
944                     *reinterpret_cast<const AmdHsaKernelConfig*>(kinput.setup));
945                output.write("    .hsaconfig\n", 15);
946            }
947           
948            dumpAmdCL2ArgsAndSamplers(output, config);
949        }
950       
951        if (doDumpCode && kinput.code != nullptr && kinput.codeSize != 0)
952        {
953            // input kernel code (main disassembly)
954            isaDisassembler->clearRelocations();
955            isaDisassembler->addRelSymbol(".gdata");
956            isaDisassembler->addRelSymbol(".ddata"); // rw data
957            isaDisassembler->addRelSymbol(".bdata"); // .bss data
958            for (const AmdCL2RelaEntry& entry: kinput.textRelocs)
959                isaDisassembler->addRelocation(entry.offset, entry.type, 
960                               cxuint(entry.symbol), entry.addend);
961   
962            output.write("    .text\n", 10);
963            isaDisassembler->setInput(kinput.codeSize, kinput.code);
964            isaDisassembler->beforeDisassemble();
965            isaDisassembler->disassemble();
966            sectionCount++;
967        }
968    }
969}
Note: See TracBrowser for help on using the repository browser.