source: CLRX/CLRadeonExtender/trunk/amdasm/DisasmROCm.cpp @ 2523

Last change on this file since 2523 was 2523, checked in by matszpk, 4 years ago

CLRadeonExtender: DisasmROCm: add arch_minor and arch_stepping and control_directive dump.

File size: 16.9 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 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 <inttypes.h>
24#include <string>
25#include <ostream>
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/ROCmBinaries.h>
32#include <CLRX/amdasm/Disassembler.h>
33#include <CLRX/utils/GPUId.h>
34#include "DisasmInternals.h"
35
36using namespace CLRX;
37
38struct AMDGPUArchValues
39{
40    uint32_t major;
41    uint32_t minor;
42    uint32_t stepping;
43    GPUDeviceType deviceType;
44};
45
46static const AMDGPUArchValues amdGpuArchValuesTbl[] =
47{
48    { 0, 0, 0, GPUDeviceType::CAPE_VERDE },
49    { 7, 0, 0, GPUDeviceType::BONAIRE },
50    { 7, 0, 1, GPUDeviceType::HAWAII },
51    { 8, 0, 0, GPUDeviceType::ICELAND },
52    { 8, 0, 1, GPUDeviceType::CARRIZO },
53    { 8, 0, 2, GPUDeviceType::ICELAND },
54    { 8, 0, 3, GPUDeviceType::FIJI },
55    { 8, 0, 4, GPUDeviceType::FIJI },
56    { 8, 1, 0, GPUDeviceType::STONEY }
57};
58
59static const size_t amdGpuArchValuesNum = sizeof(amdGpuArchValuesTbl) /
60                sizeof(AMDGPUArchValues);
61
62ROCmDisasmInput* CLRX::getROCmDisasmInputFromBinary(const ROCmBinary& binary)
63{
64    std::unique_ptr<ROCmDisasmInput> input(new ROCmDisasmInput);
65    uint32_t archMajor = 0;
66    input->archMinor = 0;
67    input->archStepping = 0;
68   
69    {
70        const cxbyte* noteContent = binary.getSectionContent(".note");
71        size_t notesSize = binary.getSectionHeader(".note").sh_size;
72        // find note about AMDGPU
73        for (size_t offset = 0; offset < notesSize; )
74        {
75            const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
76            size_t namesz = ULEV(nhdr->n_namesz);
77            size_t descsz = ULEV(nhdr->n_descsz);
78            if (usumGt(offset, namesz+descsz, notesSize))
79                throw Exception("Note offset+size out of range");
80            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
81                ::strcmp((const char*)noteContent+offset+sizeof(Elf64_Nhdr), "AMD")==0)
82            {    // AMDGPU type
83                const uint32_t* content = (const uint32_t*)
84                        (noteContent+offset+sizeof(Elf64_Nhdr) + 4);
85                archMajor = ULEV(content[1]);
86                input->archMinor = ULEV(content[2]);
87                input->archStepping = ULEV(content[3]);
88            }
89            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
90            offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
91        }
92    }
93    // determine device type
94    input->deviceType = GPUDeviceType::CAPE_VERDE;
95    if (archMajor==0)
96        input->deviceType = GPUDeviceType::CAPE_VERDE;
97    else if (archMajor==7)
98        input->deviceType = GPUDeviceType::BONAIRE;
99    else if (archMajor==8)
100        input->deviceType = GPUDeviceType::ICELAND;
101   
102    for (cxuint i = 0; i < amdGpuArchValuesNum; i++)
103        if (amdGpuArchValuesTbl[i].major==archMajor &&
104            amdGpuArchValuesTbl[i].minor==input->archMinor &&
105            amdGpuArchValuesTbl[i].stepping==input->archStepping)
106        {
107            input->deviceType = amdGpuArchValuesTbl[i].deviceType;
108            break;
109        }
110   
111    const size_t regionsNum = binary.getRegionsNum();
112    input->regions.resize(regionsNum);
113    size_t codeOffset = binary.getCode()-binary.getBinaryCode();
114    for (size_t i = 0; i < regionsNum; i++)
115    {
116        const ROCmRegion& region = binary.getRegion(i);
117        input->regions[i] = { region.regionName, region.size,
118            region.offset - codeOffset, region.isKernel };
119    }
120   
121    input->code = binary.getCode();
122    input->codeSize = binary.getCodeSize();
123    return input.release();
124}
125
126static void dumpKernelConfig(std::ostream& output, cxuint maxSgprsNum,
127             GPUArchitecture arch, const ROCmKernelConfig& config)
128{
129    output.write("    .config\n", 12);
130    size_t bufSize;
131    char buf[100];
132    const cxuint ldsShift = arch<GPUArchitecture::GCN1_1 ? 8 : 9;
133    const uint32_t pgmRsrc1 = config.computePgmRsrc1;
134    const uint32_t pgmRsrc2 = config.computePgmRsrc2;
135   
136    const cxuint dimMask = (pgmRsrc2 >> 7) & 7;
137    strcpy(buf, "        .dims ");
138    bufSize = 14;
139    if ((dimMask & 1) != 0)
140        buf[bufSize++] = 'x';
141    if ((dimMask & 2) != 0)
142        buf[bufSize++] = 'y';
143    if ((dimMask & 4) != 0)
144        buf[bufSize++] = 'z';
145    buf[bufSize++] = '\n';
146    output.write(buf, bufSize);
147   
148    bufSize = snprintf(buf, 100, "        .sgprsnum %u\n",
149              std::min((((pgmRsrc1>>6) & 0xf)<<3)+8, maxSgprsNum));
150    output.write(buf, bufSize);
151    bufSize = snprintf(buf, 100, "        .vgprsnum %u\n", ((pgmRsrc1 & 0x3f)<<2)+4);
152    output.write(buf, bufSize);
153    output.write(buf, bufSize);
154    if ((pgmRsrc1 & (1U<<20)) != 0)
155        output.write("        .privmode\n", 18);
156    if ((pgmRsrc1 & (1U<<22)) != 0)
157        output.write("        .debugmode\n", 19);
158    if ((pgmRsrc1 & (1U<<21)) != 0)
159        output.write("        .dx10clamp\n", 19);
160    if ((pgmRsrc1 & (1U<<23)) != 0)
161        output.write("        .ieeemode\n", 18);
162    if ((pgmRsrc2 & 0x400) != 0)
163        output.write("        .tgsize\n", 16);
164   
165    bufSize = snprintf(buf, 100, "        .floatmode 0x%02x\n", (pgmRsrc1>>12) & 0xff);
166    output.write(buf, bufSize);
167    bufSize = snprintf(buf, 100, "        .priority %u\n", (pgmRsrc1>>10) & 3);
168    output.write(buf, bufSize);
169    if (((pgmRsrc1>>24) & 0x7f) != 0)
170    {
171        bufSize = snprintf(buf, 100, "        .exceptions 0x%02x\n",
172                   (pgmRsrc1>>24) & 0x7f);
173        output.write(buf, bufSize);
174    }
175    const cxuint localSize = ((pgmRsrc2>>15) & 0x1ff) << ldsShift;
176    if (localSize!=0)
177    {
178        bufSize = snprintf(buf, 100, "        .localsize %u\n", localSize);
179        output.write(buf, bufSize);
180    }
181    bufSize = snprintf(buf, 100, "        .userdatanum %u\n", (pgmRsrc2>>1) & 0x1f);
182    output.write(buf, bufSize);
183   
184    bufSize = snprintf(buf, 100, "        .pgmrsrc1 0x%08x\n", pgmRsrc1);
185    output.write(buf, bufSize);
186    bufSize = snprintf(buf, 100, "        .pgmrsrc2 0x%08x\n", pgmRsrc2);
187    output.write(buf, bufSize);
188   
189    bufSize = snprintf(buf, 100, "        .codeversion %u, %u\n",
190                   config.amdCodeVersionMajor, config.amdCodeVersionMinor);
191    output.write(buf, bufSize);
192    bufSize = snprintf(buf, 100, "        .machine %hu, %hu, %hu, %hu\n",
193                   config.amdMachineKind, config.amdMachineMajor,
194                   config.amdMachineMinor, config.amdMachineStepping);
195    output.write(buf, bufSize);
196    bufSize = snprintf(buf, 100, "        .kernel_code_entry_offset 0x%" PRIx64 "\n",
197                       config.kernelCodeEntryOffset);
198    output.write(buf, bufSize);
199    if (config.kernelCodePrefetchOffset!=0)
200    {
201        bufSize = snprintf(buf, 100,
202                   "        .kernel_code_prefetch_offset 0x%" PRIx64 "\n",
203                           config.kernelCodePrefetchOffset);
204        output.write(buf, bufSize);
205    }
206    if (config.kernelCodePrefetchSize!=0)
207    {
208        bufSize = snprintf(buf, 100, "        .kernel_code_prefetch_size %" PRIu64 "\n",
209                           config.kernelCodePrefetchSize);
210        output.write(buf, bufSize);
211    }
212    if (config.maxScrachBackingMemorySize!=0)
213    {
214        bufSize = snprintf(buf, 100, "        .max_scratch_backing_memory %" PRIu64 "\n",
215                           config.maxScrachBackingMemorySize);
216        output.write(buf, bufSize);
217    }
218   
219    const uint16_t sgprFlags = config.enableSpgrRegisterFlags;
220    if ((sgprFlags&1) != 0)
221        output.write("        .use_private_segment_buffer\n", 36);
222    if ((sgprFlags&2) != 0)
223        output.write("        .use_dispatch_ptr\n", 26);
224    if ((sgprFlags&4) != 0)
225        output.write("        .use_queue_ptr\n", 24);
226    if ((sgprFlags&8) != 0)
227        output.write("        .use_kernarg_segment_ptr\n", 33);
228    if ((sgprFlags&16) != 0)
229        output.write("        .use_dispatch_id\n", 25);
230    if ((sgprFlags&32) != 0)
231        output.write("        .use_flat_scratch_init\n", 31);
232    if ((sgprFlags&64) != 0)
233        output.write("        .use_private_segment_size\n", 34);
234    if ((sgprFlags&128) != 0)
235        output.write("        .use_grid_workgroup_count_x\n", 36);
236    if ((sgprFlags&256) != 0)
237        output.write("        .use_grid_workgroup_count_y\n", 36);
238    if ((sgprFlags&512) != 0)
239        output.write("        .use_grid_workgroup_count_z\n", 36);
240    const uint16_t featureFlags = config.enableFeatureFlags;
241    if ((featureFlags&1) != 0)
242        output.write("        .use_ordered_append_gds\n", 32);
243    bufSize = snprintf(buf, 100, "        .private_elem_size %u\n",
244                       2U<<((featureFlags>>1)&3));
245    output.write(buf, bufSize);
246    if ((featureFlags&8) != 0)
247        output.write("        .use_ptr64\n", 19);
248    if ((featureFlags&16) != 0)
249        output.write("        .use_dynamic_call_stack\n", 32);
250    if ((featureFlags&32) != 0)
251        output.write("        .use_debug_enabled\n", 27);
252    if ((featureFlags&64) != 0)
253        output.write("        .use_xnack_enabled\n", 27);
254   
255    if (config.workitemPrivateSegmentSize!=0)
256    {
257        bufSize = snprintf(buf, 100, "        .workitem_private_segment_size %u\n",
258                         config.workitemPrivateSegmentSize);
259        output.write(buf, bufSize);
260    }
261    if (config.workgroupGroupSegmentSize!=0)
262    {
263        bufSize = snprintf(buf, 100, "        .workgroup_group_segment_size %u\n",
264                         config.workgroupGroupSegmentSize);
265        output.write(buf, bufSize);
266    }
267    if (config.gdsSegmentSize!=0)
268    {
269        bufSize = snprintf(buf, 100, "        .gds_segment_size %u\n",
270                         config.gdsSegmentSize);
271        output.write(buf, bufSize);
272    }
273    if (config.kernargSegmentSize!=0)
274    {
275        bufSize = snprintf(buf, 100, "        .kernarg_segment_size %" PRIu64 "\n",
276                         config.kernargSegmentSize);
277        output.write(buf, bufSize);
278    }
279    if (config.workgroupFbarrierCount!=0)
280    {
281        bufSize = snprintf(buf, 100, "        .workgroup_fbarrier_count %u\n",
282                         config.workgroupFbarrierCount);
283        output.write(buf, bufSize);
284    }
285    if (config.wavefrontSgprCount!=0)
286    {
287        bufSize = snprintf(buf, 100, "        .wavefront_sgpr_count %hu\n",
288                         config.wavefrontSgprCount);
289        output.write(buf, bufSize);
290    }
291    if (config.workitemVgprCount!=0)
292    {
293        bufSize = snprintf(buf, 100, "        .workitem_vgpr_count %hu\n",
294                         config.workitemVgprCount);
295        output.write(buf, bufSize);
296    }
297    if (config.reservedVgprFirst!=0)
298    {
299        bufSize = snprintf(buf, 100, "        .reserved_vgpr_first %hu\n",
300                         config.reservedVgprFirst);
301        output.write(buf, bufSize);
302    }
303    if (config.reservedVgprCount!=0)
304    {
305        bufSize = snprintf(buf, 100, "        .reserved_vgpr_count %hu\n",
306                         config.reservedVgprCount);
307        output.write(buf, bufSize);
308    }
309    if (config.reservedSgprFirst!=0)
310    {
311        bufSize = snprintf(buf, 100, "        .reserved_sgpr_first %hu\n",
312                         config.reservedSgprFirst);
313        output.write(buf, bufSize);
314    }
315    if (config.reservedSgprCount!=0)
316    {
317        bufSize = snprintf(buf, 100, "        .reserved_sgpr_count %hu\n",
318                         config.reservedSgprCount);
319        output.write(buf, bufSize);
320    }
321    if (config.debugWavefrontPrivateSegmentOffsetSgpr!=0)
322    {
323        bufSize = snprintf(buf, 100, "        "
324                        ".debug_wavefront_private_segment_offset_sgpr %hu\n",
325                         config.debugWavefrontPrivateSegmentOffsetSgpr);
326        output.write(buf, bufSize);
327    }
328    if (config.debugPrivateSegmentBufferSgpr!=0)
329    {
330        bufSize = snprintf(buf, 100, "        .debug_private_segment_buffer_sgpr %hu\n",
331                         config.debugPrivateSegmentBufferSgpr);
332        output.write(buf, bufSize);
333    }
334    bufSize = snprintf(buf, 100, "        .kernarg_segment_align %u\n",
335                     1U<<(config.kernargSegmentAlignment));
336    output.write(buf, bufSize);
337    bufSize = snprintf(buf, 100, "        .group_segment_align %u\n",
338                     1U<<(config.groupSegmentAlignment));
339    output.write(buf, bufSize);
340    bufSize = snprintf(buf, 100, "        .private_segment_align %u\n",
341                     1U<<(config.privateSegmentAlignment));
342    output.write(buf, bufSize);
343    bufSize = snprintf(buf, 100, "        .wavefront_size %u\n",
344                     1U<<(config.wavefrontSize));
345    output.write(buf, bufSize);
346    bufSize = snprintf(buf, 100, "        .call_convention 0x%x\n",
347                     config.callConvention);
348    output.write(buf, bufSize);
349    if (config.runtimeLoaderKernelSymbol!=0)
350    {
351        bufSize = snprintf(buf, 100,
352                   "        .runtime_loader_kernel_symbol 0x%" PRIx64 "\n",
353                         config.runtimeLoaderKernelSymbol);
354        output.write(buf, bufSize);
355    }
356   
357    output.write("    .control_directive\n", 23);
358    printDisasmData(sizeof config.controlDirective, config.controlDirective, output, true);
359}
360
361void CLRX::disassembleROCm(std::ostream& output, const ROCmDisasmInput* rocmInput,
362           ISADisassembler* isaDisassembler, size_t& sectionCount, Flags flags)
363{
364    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
365    const bool doMetadata = ((flags & (DISASM_METADATA|DISASM_CONFIG)) != 0);
366    const bool doDumpCode = ((flags & DISASM_DUMPCODE) != 0);
367    const bool doDumpConfig = ((flags & DISASM_CONFIG) != 0);
368   
369    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(rocmInput->deviceType);
370    const cxuint maxSgprsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
371   
372    {
373        char buf[40];
374        size_t size = snprintf(buf, 40, ".arch_minor %u\n", rocmInput->archMinor);
375        output.write(buf, size);
376        size = snprintf(buf, 40, ".arch_stepping %u\n", rocmInput->archStepping);
377        output.write(buf, size);
378    }
379   
380    for (const ROCmDisasmRegionInput& rinput: rocmInput->regions)
381        if (rinput.isKernel)
382        {
383            output.write(".kernel ", 8);
384            output.write(rinput.regionName.c_str(), rinput.regionName.size());
385            output.put('\n');
386            if (doMetadata && doDumpConfig)
387                dumpKernelConfig(output, maxSgprsNum, arch,
388                     *reinterpret_cast<const ROCmKernelConfig*>(
389                             rocmInput->code + rinput.offset));
390        }
391   
392    const size_t regionsNum = rocmInput->regions.size();
393    typedef std::pair<size_t, size_t> SortEntry;
394    std::unique_ptr<SortEntry[]> sorted(new SortEntry[regionsNum]);
395    for (size_t i = 0; i < regionsNum; i++)
396        sorted[i] = std::make_pair(rocmInput->regions[i].offset, i);
397    mapSort(sorted.get(), sorted.get() + regionsNum);
398   
399    if (rocmInput->code != nullptr && rocmInput->codeSize != 0)
400    {
401        const cxbyte* code = rocmInput->code;
402        output.write(".text\n", 6);
403        for (size_t i = 0; i < regionsNum; i++)
404        {
405            const ROCmDisasmRegionInput& region = rocmInput->regions[sorted[i].second];
406            output.write(region.regionName.c_str(), region.regionName.size());
407            output.write(":\n", 2);
408            if (region.isKernel)
409            {
410                if (doMetadata)
411                {
412                    if (!doDumpConfig)
413                        printDisasmData(0x100, code + region.offset, output, true);
414                    else
415                        output.write(".skip 256\n", 10);
416                }
417                if (doDumpCode)
418                {
419                    isaDisassembler->setInput(region.size-256, code + region.offset+256,
420                                    region.offset+256);
421                    isaDisassembler->setDontPrintLabels(i+1<regionsNum);
422                    isaDisassembler->beforeDisassemble();
423                    isaDisassembler->disassemble();
424                }
425            }
426            else if (doDumpData)
427            {
428                output.write(".global ", 8);
429                output.write(region.regionName.c_str(), region.regionName.size());
430                output.write("\n", 1);
431                printDisasmData(region.size, code + region.offset, output, true);
432            }
433        }
434    }
435}
Note: See TracBrowser for help on using the repository browser.