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

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

CLRadeonExtender: DisasmROCm: Add required '.config' pseudo-op after '.control_directive' before metadata info printing.

File size: 34.5 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 <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
38ROCmDisasmInput* CLRX::getROCmDisasmInputFromBinary(const ROCmBinary& binary)
39{
40    std::unique_ptr<ROCmDisasmInput> input(new ROCmDisasmInput);
41    input->deviceType = binary.determineGPUDeviceType(input->archMinor,
42                              input->archStepping);
43   
44    const size_t regionsNum = binary.getRegionsNum();
45    input->regions.resize(regionsNum);
46    size_t codeOffset = binary.getCode()-binary.getBinaryCode();
47    // ger regions of code
48    for (size_t i = 0; i < regionsNum; i++)
49    {
50        const ROCmRegion& region = binary.getRegion(i);
51        input->regions[i] = { region.regionName, size_t(region.size),
52            size_t(region.offset - codeOffset), region.type };
53    }
54    // setup code
55    input->eflags = ULEV(binary.getHeader().e_flags);
56    input->code = binary.getCode();
57    input->codeSize = binary.getCodeSize();
58    input->metadata = binary.getMetadata();
59    input->metadataSize = binary.getMetadataSize();
60    input->globalData = binary.getGlobalData();
61    input->globalDataSize = binary.getGlobalDataSize();
62    input->target = binary.getTarget();
63    input->newBinFormat = binary.isNewBinaryFormat();
64    return input.release();
65}
66
67void CLRX::dumpAMDHSAConfig(std::ostream& output, cxuint maxSgprsNum,
68             GPUArchitecture arch, const ROCmKernelConfig& config, bool amdhsaPrefix)
69{
70    // convert to native-endian
71    uint32_t amdCodeVersionMajor = ULEV(config.amdCodeVersionMajor);
72    uint32_t amdCodeVersionMinor = ULEV(config.amdCodeVersionMinor);
73    uint16_t amdMachineKind = ULEV(config.amdMachineKind);
74    uint16_t amdMachineMajor = ULEV(config.amdMachineMajor);
75    uint16_t amdMachineMinor = ULEV(config.amdMachineMinor);
76    uint16_t amdMachineStepping = ULEV(config.amdMachineStepping);
77    uint64_t kernelCodeEntryOffset = ULEV(config.kernelCodeEntryOffset);
78    uint64_t kernelCodePrefetchOffset = ULEV(config.kernelCodePrefetchOffset);
79    uint64_t kernelCodePrefetchSize = ULEV(config.kernelCodePrefetchSize);
80    uint64_t maxScrachBackingMemorySize = ULEV(config.maxScrachBackingMemorySize);
81    uint32_t computePgmRsrc1 = ULEV(config.computePgmRsrc1);
82    uint32_t computePgmRsrc2 = ULEV(config.computePgmRsrc2);
83    uint16_t enableSgprRegisterFlags = ULEV(config.enableSgprRegisterFlags);
84    uint16_t enableFeatureFlags = ULEV(config.enableFeatureFlags);
85    uint32_t workitemPrivateSegmentSize = ULEV(config.workitemPrivateSegmentSize);
86    uint32_t workgroupGroupSegmentSize = ULEV(config.workgroupGroupSegmentSize);
87    uint32_t gdsSegmentSize = ULEV(config.gdsSegmentSize);
88    uint64_t kernargSegmentSize = ULEV(config.kernargSegmentSize);
89    uint32_t workgroupFbarrierCount = ULEV(config.workgroupFbarrierCount);
90    uint16_t wavefrontSgprCount = ULEV(config.wavefrontSgprCount);
91    uint16_t workitemVgprCount = ULEV(config.workitemVgprCount);
92    uint16_t reservedVgprFirst = ULEV(config.reservedVgprFirst);
93    uint16_t reservedVgprCount = ULEV(config.reservedVgprCount);
94    uint16_t reservedSgprFirst = ULEV(config.reservedSgprFirst);
95    uint16_t reservedSgprCount = ULEV(config.reservedSgprCount);
96    uint16_t debugWavefrontPrivateSegmentOffsetSgpr =
97            ULEV(config.debugWavefrontPrivateSegmentOffsetSgpr);
98    uint16_t debugPrivateSegmentBufferSgpr = ULEV(config.debugPrivateSegmentBufferSgpr);
99    uint32_t callConvention = ULEV(config.callConvention);
100    uint64_t runtimeLoaderKernelSymbol = ULEV(config.runtimeLoaderKernelSymbol);
101   
102    size_t bufSize;
103    char buf[100];
104    const cxuint ldsShift = arch<GPUArchitecture::GCN1_1 ? 8 : 9;
105    const uint32_t pgmRsrc1 = computePgmRsrc1;
106    const uint32_t pgmRsrc2 = computePgmRsrc2;
107   
108    const cxuint dimMask = (pgmRsrc2 >> 7) & 7;
109    // print dims (hsadims for gallium): .[hsa_]dims xyz
110    if (!amdhsaPrefix)
111    {
112        strcpy(buf, "        .dims ");
113        bufSize = 14;
114    }
115    else
116    {
117        strcpy(buf, "        .hsa_dims ");
118        bufSize = 18;
119    }
120    if ((dimMask & 1) != 0)
121        buf[bufSize++] = 'x';
122    if ((dimMask & 2) != 0)
123        buf[bufSize++] = 'y';
124    if ((dimMask & 4) != 0)
125        buf[bufSize++] = 'z';
126    buf[bufSize++] = '\n';
127    output.write(buf, bufSize);
128   
129    if (!amdhsaPrefix)
130    {
131        // print in original form
132        // get sgprsnum and vgprsnum from PGMRSRC1
133        bufSize = snprintf(buf, 100, "        .sgprsnum %u\n",
134                std::min((((pgmRsrc1>>6) & 0xf)<<3)+8, maxSgprsNum));
135        output.write(buf, bufSize);
136        bufSize = snprintf(buf, 100, "        .vgprsnum %u\n", ((pgmRsrc1 & 0x3f)<<2)+4);
137        output.write(buf, bufSize);
138        if ((pgmRsrc1 & (1U<<20)) != 0)
139            output.write("        .privmode\n", 18);
140        if ((pgmRsrc1 & (1U<<22)) != 0)
141            output.write("        .debugmode\n", 19);
142        if ((pgmRsrc1 & (1U<<21)) != 0)
143            output.write("        .dx10clamp\n", 19);
144        if ((pgmRsrc1 & (1U<<23)) != 0)
145            output.write("        .ieeemode\n", 18);
146        if ((pgmRsrc2 & 0x400) != 0)
147            output.write("        .tgsize\n", 16);
148       
149        bufSize = snprintf(buf, 100, "        .floatmode 0x%02x\n", (pgmRsrc1>>12) & 0xff);
150        output.write(buf, bufSize);
151        bufSize = snprintf(buf, 100, "        .priority %u\n", (pgmRsrc1>>10) & 3);
152        output.write(buf, bufSize);
153        if (((pgmRsrc1>>24) & 0x7f) != 0)
154        {
155            bufSize = snprintf(buf, 100, "        .exceptions 0x%02x\n",
156                    (pgmRsrc1>>24) & 0x7f);
157            output.write(buf, bufSize);
158        }
159        const cxuint localSize = ((pgmRsrc2>>15) & 0x1ff) << ldsShift;
160        if (localSize!=0)
161        {
162            bufSize = snprintf(buf, 100, "        .localsize %u\n", localSize);
163            output.write(buf, bufSize);
164        }
165        bufSize = snprintf(buf, 100, "        .userdatanum %u\n", (pgmRsrc2>>1) & 0x1f);
166        output.write(buf, bufSize);
167       
168        bufSize = snprintf(buf, 100, "        .pgmrsrc1 0x%08x\n", pgmRsrc1);
169        output.write(buf, bufSize);
170        bufSize = snprintf(buf, 100, "        .pgmrsrc2 0x%08x\n", pgmRsrc2);
171        output.write(buf, bufSize);
172    }
173    else
174    {
175        // print with 'hsa_' prefix (for gallium)
176        // get sgprsnum and vgprsnum from PGMRSRC1
177        bufSize = snprintf(buf, 100, "        .hsa_sgprsnum %u\n",
178                std::min((((pgmRsrc1>>6) & 0xf)<<3)+8, maxSgprsNum));
179        output.write(buf, bufSize);
180        bufSize = snprintf(buf, 100, "        .hsa_vgprsnum %u\n", ((pgmRsrc1 & 0x3f)<<2)+4);
181        output.write(buf, bufSize);
182        if ((pgmRsrc1 & (1U<<20)) != 0)
183            output.write("        .hsa_privmode\n", 22);
184        if ((pgmRsrc1 & (1U<<22)) != 0)
185            output.write("        .hsa_debugmode\n", 23);
186        if ((pgmRsrc1 & (1U<<21)) != 0)
187            output.write("        .hsa_dx10clamp\n", 23);
188        if ((pgmRsrc1 & (1U<<23)) != 0)
189            output.write("        .hsa_ieeemode\n", 22);
190        if ((pgmRsrc2 & 0x400) != 0)
191            output.write("        .hsa_tgsize\n", 20);
192       
193        bufSize = snprintf(buf, 100, "        .hsa_floatmode 0x%02x\n",
194                    (pgmRsrc1>>12) & 0xff);
195        output.write(buf, bufSize);
196        bufSize = snprintf(buf, 100, "        .hsa_priority %u\n",
197                    (pgmRsrc1>>10) & 3);
198        output.write(buf, bufSize);
199        if (((pgmRsrc1>>24) & 0x7f) != 0)
200        {
201            bufSize = snprintf(buf, 100, "        .hsa_exceptions 0x%02x\n",
202                    (pgmRsrc1>>24) & 0x7f);
203            output.write(buf, bufSize);
204        }
205        const cxuint localSize = ((pgmRsrc2>>15) & 0x1ff) << ldsShift;
206        if (localSize!=0)
207        {
208            bufSize = snprintf(buf, 100, "        .hsa_localsize %u\n", localSize);
209            output.write(buf, bufSize);
210        }
211        bufSize = snprintf(buf, 100, "        .hsa_userdatanum %u\n", (pgmRsrc2>>1) & 0x1f);
212        output.write(buf, bufSize);
213       
214        bufSize = snprintf(buf, 100, "        .hsa_pgmrsrc1 0x%08x\n", pgmRsrc1);
215        output.write(buf, bufSize);
216        bufSize = snprintf(buf, 100, "        .hsa_pgmrsrc2 0x%08x\n", pgmRsrc2);
217        output.write(buf, bufSize);
218    }
219   
220    bufSize = snprintf(buf, 100, "        .codeversion %u, %u\n",
221                   amdCodeVersionMajor, amdCodeVersionMinor);
222    output.write(buf, bufSize);
223    bufSize = snprintf(buf, 100, "        .machine %hu, %hu, %hu, %hu\n",
224                   amdMachineKind, amdMachineMajor,
225                   amdMachineMinor, amdMachineStepping);
226    output.write(buf, bufSize);
227    bufSize = snprintf(buf, 100, "        .kernel_code_entry_offset 0x%" PRIx64 "\n",
228                       kernelCodeEntryOffset);
229    output.write(buf, bufSize);
230    if (kernelCodePrefetchOffset!=0)
231    {
232        bufSize = snprintf(buf, 100,
233                   "        .kernel_code_prefetch_offset 0x%" PRIx64 "\n",
234                           kernelCodePrefetchOffset);
235        output.write(buf, bufSize);
236    }
237    if (kernelCodePrefetchSize!=0)
238    {
239        bufSize = snprintf(buf, 100, "        .kernel_code_prefetch_size %" PRIu64 "\n",
240                           kernelCodePrefetchSize);
241        output.write(buf, bufSize);
242    }
243    if (maxScrachBackingMemorySize!=0)
244    {
245        bufSize = snprintf(buf, 100, "        .max_scratch_backing_memory %" PRIu64 "\n",
246                           maxScrachBackingMemorySize);
247        output.write(buf, bufSize);
248    }
249   
250    const uint16_t sgprFlags = enableSgprRegisterFlags;
251    // print SGPRregister flags (features)
252    if ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER) != 0)
253        output.write("        .use_private_segment_buffer\n", 36);
254    if ((sgprFlags&ROCMFLAG_USE_DISPATCH_PTR) != 0)
255        output.write("        .use_dispatch_ptr\n", 26);
256    if ((sgprFlags&ROCMFLAG_USE_QUEUE_PTR) != 0)
257        output.write("        .use_queue_ptr\n", 23);
258    if ((sgprFlags&ROCMFLAG_USE_KERNARG_SEGMENT_PTR) != 0)
259        output.write("        .use_kernarg_segment_ptr\n", 33);
260    if ((sgprFlags&ROCMFLAG_USE_DISPATCH_ID) != 0)
261        output.write("        .use_dispatch_id\n", 25);
262    if ((sgprFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT) != 0)
263        output.write("        .use_flat_scratch_init\n", 31);
264    if ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE) != 0)
265        output.write("        .use_private_segment_size\n", 34);
266   
267    if ((sgprFlags&(7U<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT)) != 0)
268    {
269        // print .use_grid_workgroup_count xyz (dimensions)
270        strcpy(buf, "        .use_grid_workgroup_count ");
271        bufSize = 34;
272        if ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_X) != 0)
273            buf[bufSize++] = 'x';
274        if ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Y) != 0)
275            buf[bufSize++] = 'y';
276        if ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Z) != 0)
277            buf[bufSize++] = 'z';
278        buf[bufSize++] = '\n';
279        output.write(buf, bufSize);
280    }
281   
282    const uint16_t featureFlags = enableFeatureFlags;
283    if ((featureFlags&ROCMFLAG_USE_ORDERED_APPEND_GDS) != 0)
284        output.write("        .use_ordered_append_gds\n", 32);
285    bufSize = snprintf(buf, 100, "        .private_elem_size %u\n",
286                       2U<<((featureFlags>>ROCMFLAG_PRIVATE_ELEM_SIZE_BIT)&3));
287    output.write(buf, bufSize);
288    if ((featureFlags&ROCMFLAG_USE_PTR64) != 0)
289        output.write("        .use_ptr64\n", 19);
290    if ((featureFlags&ROCMFLAG_USE_DYNAMIC_CALL_STACK) != 0)
291        output.write("        .use_dynamic_call_stack\n", 32);
292    if ((featureFlags&ROCMFLAG_USE_DEBUG_ENABLED) != 0)
293        output.write("        .use_debug_enabled\n", 27);
294    if ((featureFlags&ROCMFLAG_USE_XNACK_ENABLED) != 0)
295        output.write("        .use_xnack_enabled\n", 27);
296   
297    if (workitemPrivateSegmentSize!=0)
298    {
299        bufSize = snprintf(buf, 100, "        .workitem_private_segment_size %u\n",
300                         workitemPrivateSegmentSize);
301        output.write(buf, bufSize);
302    }
303    if (workgroupGroupSegmentSize!=0)
304    {
305        bufSize = snprintf(buf, 100, "        .workgroup_group_segment_size %u\n",
306                         workgroupGroupSegmentSize);
307        output.write(buf, bufSize);
308    }
309    if (gdsSegmentSize!=0)
310    {
311        bufSize = snprintf(buf, 100, "        .gds_segment_size %u\n",
312                         gdsSegmentSize);
313        output.write(buf, bufSize);
314    }
315    if (kernargSegmentSize!=0)
316    {
317        bufSize = snprintf(buf, 100, "        .kernarg_segment_size %" PRIu64 "\n",
318                         kernargSegmentSize);
319        output.write(buf, bufSize);
320    }
321    if (workgroupFbarrierCount!=0)
322    {
323        bufSize = snprintf(buf, 100, "        .workgroup_fbarrier_count %u\n",
324                         workgroupFbarrierCount);
325        output.write(buf, bufSize);
326    }
327    if (wavefrontSgprCount!=0)
328    {
329        bufSize = snprintf(buf, 100, "        .wavefront_sgpr_count %hu\n",
330                         wavefrontSgprCount);
331        output.write(buf, bufSize);
332    }
333    if (workitemVgprCount!=0)
334    {
335        bufSize = snprintf(buf, 100, "        .workitem_vgpr_count %hu\n",
336                         workitemVgprCount);
337        output.write(buf, bufSize);
338    }
339    if (reservedVgprCount!=0)
340    {
341        bufSize = snprintf(buf, 100, "        .reserved_vgprs %hu, %hu\n",
342                     reservedVgprFirst, uint16_t(reservedVgprFirst+reservedVgprCount-1));
343        output.write(buf, bufSize);
344    }
345    if (reservedSgprCount!=0)
346    {
347        bufSize = snprintf(buf, 100, "        .reserved_sgprs %hu, %hu\n",
348                     reservedSgprFirst, uint16_t(reservedSgprFirst+reservedSgprCount-1));
349        output.write(buf, bufSize);
350    }
351    if (debugWavefrontPrivateSegmentOffsetSgpr!=0)
352    {
353        bufSize = snprintf(buf, 100, "        "
354                        ".debug_wavefront_private_segment_offset_sgpr %hu\n",
355                         debugWavefrontPrivateSegmentOffsetSgpr);
356        output.write(buf, bufSize);
357    }
358    if (debugPrivateSegmentBufferSgpr!=0)
359    {
360        bufSize = snprintf(buf, 100, "        .debug_private_segment_buffer_sgpr %hu\n",
361                         debugPrivateSegmentBufferSgpr);
362        output.write(buf, bufSize);
363    }
364    bufSize = snprintf(buf, 100, "        .kernarg_segment_align %u\n",
365                     1U<<(config.kernargSegmentAlignment));
366    output.write(buf, bufSize);
367    bufSize = snprintf(buf, 100, "        .group_segment_align %u\n",
368                     1U<<(config.groupSegmentAlignment));
369    output.write(buf, bufSize);
370    bufSize = snprintf(buf, 100, "        .private_segment_align %u\n",
371                     1U<<(config.privateSegmentAlignment));
372    output.write(buf, bufSize);
373    bufSize = snprintf(buf, 100, "        .wavefront_size %u\n",
374                     1U<<(config.wavefrontSize));
375    output.write(buf, bufSize);
376    bufSize = snprintf(buf, 100, "        .call_convention 0x%x\n",
377                     callConvention);
378    output.write(buf, bufSize);
379    if (runtimeLoaderKernelSymbol!=0)
380    {
381        bufSize = snprintf(buf, 100,
382                   "        .runtime_loader_kernel_symbol 0x%" PRIx64 "\n",
383                         runtimeLoaderKernelSymbol);
384        output.write(buf, bufSize);
385    }
386    // new section, control_directive, outside .config
387    output.write("    .control_directive\n", 23);
388    printDisasmData(sizeof config.controlDirective, config.controlDirective, output, true);
389}
390
391static void dumpKernelConfig(std::ostream& output, cxuint maxSgprsNum,
392             GPUArchitecture arch, const ROCmKernelConfig& config)
393{
394    output.write("    .config\n", 12);
395    dumpAMDHSAConfig(output, maxSgprsNum, arch, config);
396}
397
398// routine to disassembly code in AMD HSA form (kernel with HSA config)
399void CLRX::disassembleAMDHSACode(std::ostream& output,
400            const std::vector<ROCmDisasmRegionInput>& regions,
401            size_t codeSize, const cxbyte* code, ISADisassembler* isaDisassembler,
402            Flags flags)
403{
404    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
405    const bool doMetadata = ((flags & (DISASM_METADATA|DISASM_CONFIG)) != 0);
406    const bool doDumpCode = ((flags & DISASM_DUMPCODE) != 0);
407    const bool doDumpConfig = ((flags & DISASM_CONFIG) != 0);
408   
409    const size_t regionsNum = regions.size();
410    typedef std::pair<size_t, size_t> SortEntry;
411    std::unique_ptr<SortEntry[]> sorted(new SortEntry[regionsNum]);
412    for (size_t i = 0; i < regionsNum; i++)
413        sorted[i] = std::make_pair(regions[i].offset, i);
414    mapSort(sorted.get(), sorted.get() + regionsNum);
415   
416    output.write(".text\n", 6);
417    // clear labels
418    isaDisassembler->clearNumberedLabels();
419   
420    /// analyze code with collecting labels
421    for (size_t i = 0; i < regionsNum; i++)
422    {
423        const ROCmDisasmRegionInput& region = regions[sorted[i].second];
424        if ((region.type==ROCmRegionType::KERNEL ||
425             region.type==ROCmRegionType::FKERNEL) && doDumpCode)
426        {
427            // kernel code begin after HSA config
428            isaDisassembler->setInput(region.size-256, code + region.offset+256,
429                                region.offset+256);
430            isaDisassembler->analyzeBeforeDisassemble();
431        }
432        isaDisassembler->addNamedLabel(region.offset, region.regionName);
433    }
434    isaDisassembler->prepareLabelsAndRelocations();
435   
436    ISADisassembler::LabelIter curLabel;
437    ISADisassembler::NamedLabelIter curNamedLabel;
438    const auto& labels = isaDisassembler->getLabels();
439    const auto& namedLabels = isaDisassembler->getNamedLabels();
440    // real disassemble
441    size_t prevRegionPos = 0;
442    for (size_t i = 0; i < regionsNum; i++)
443    {
444        const ROCmDisasmRegionInput& region = regions[sorted[i].second];
445        // set labelIters to previous position
446        isaDisassembler->setInput(prevRegionPos, code + region.offset,
447                                region.offset, prevRegionPos);
448        curLabel = std::lower_bound(labels.begin(), labels.end(), prevRegionPos);
449        curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
450            std::make_pair(prevRegionPos, CString()),
451                [](const std::pair<size_t,CString>& a,
452                                const std::pair<size_t, CString>& b)
453                { return a.first < b.first; });
454        // write labels to current region position
455        isaDisassembler->writeLabelsToPosition(0, curLabel, curNamedLabel);
456        isaDisassembler->flushOutput();
457       
458        size_t dataSize = codeSize - region.offset;
459        if (i+1<regionsNum)
460        {
461            // if not last region, then set size as (next_offset - this_offset)
462            const ROCmDisasmRegionInput& newRegion = regions[sorted[i+1].second];
463            dataSize = newRegion.offset - region.offset;
464        }
465        if (region.type!=ROCmRegionType::DATA)
466        {
467            if (doMetadata)
468            {
469                if (!doDumpConfig)
470                    printDisasmData(0x100, code + region.offset, output, true);
471                else    // skip, config was dumped in kernel configuration
472                    output.write(".skip 256\n", 10);
473            }
474           
475            if (doDumpCode)
476            {
477                // dump code of region
478                isaDisassembler->setInput(dataSize-256, code + region.offset+256,
479                                region.offset+256, region.offset+1);
480                isaDisassembler->setDontPrintLabels(i+1<regionsNum);
481                isaDisassembler->disassemble();
482            }
483            prevRegionPos = region.offset + dataSize + 1;
484        }
485        else if (doDumpData)
486        {
487            output.write(".global ", 8);
488            output.write(region.regionName.c_str(), region.regionName.size());
489            output.write("\n", 1);
490            printDisasmData(dataSize, code + region.offset, output, true);
491            prevRegionPos = region.offset+1;
492        }
493    }
494   
495    if (regionsNum!=0 && regions[sorted[regionsNum-1].second].type==ROCmRegionType::DATA)
496    {
497        // if last region is data then finishing dumping data
498        const ROCmDisasmRegionInput& region = regions[sorted[regionsNum-1].second];
499        // set labelIters to previous position
500        isaDisassembler->setInput(prevRegionPos, code + region.offset+region.size,
501                                region.offset+region.size, prevRegionPos);
502        curLabel = std::lower_bound(labels.begin(), labels.end(), prevRegionPos);
503        curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
504            std::make_pair(prevRegionPos, CString()),
505                [](const std::pair<size_t,CString>& a,
506                                const std::pair<size_t, CString>& b)
507                { return a.first < b.first; });
508        // if last region is not kernel, then print labels after last region
509        isaDisassembler->writeLabelsToPosition(0, curLabel, curNamedLabel);
510        isaDisassembler->flushOutput();
511        isaDisassembler->writeLabelsToEnd(region.size, curLabel, curNamedLabel);
512        isaDisassembler->flushOutput();
513    }
514}
515
516static inline bool hasValue(cxuint value)
517{ return value!=BINGEN_NOTSUPPLIED && value!=BINGEN_DEFAULT; }
518
519static inline bool hasValue(uint64_t value)
520{ return value!=BINGEN64_NOTSUPPLIED && value!=BINGEN64_DEFAULT; }
521
522static const char* disasmROCmValueKindNames[] =
523{
524    "value", "globalbuf", "dynshptr", "sampler", "image", "pipe", "queue",
525    "gox", "goy", "goz", "none", "printfbuf", "defqueue", "complact"
526};
527
528static const char* disasmROCmValueTypeNames[] =
529{ "struct", "i8", "u8", "i16", "u16", "f16", "i32", "u32", "f32", "i64", "u64", "f64" };
530
531static const char* disasmROCmAddressSpaces[] =
532{ "none", "private", "global", "constant", "local", "generic", "region" };
533
534static const char* disasmROCmAccessQuals[] =
535{ "default", "read_only", "write_only", "read_write" };
536
537static void dumpKernelMetadataInfo(std::ostream& output, const ROCmKernelMetadata& kernel)
538{
539    output.write("    .config\n", 12);
540    output.write("        .md_symname ", 20);
541    output.write(kernel.symbolName.c_str(), kernel.symbolName.size());
542    output.write("\n", 1);
543    output.write("        .md_language \"", 22);
544    {
545        std::string langName = escapeStringCStyle(kernel.language);
546        output.write(langName.c_str(), langName.size());
547    }
548    size_t bufSize = 0;
549    char buf[100];
550    if (kernel.langVersion[0] != BINGEN_NOTSUPPLIED)
551    {
552        output.write("\", ", 3);
553        bufSize = snprintf(buf, 100, "%u, %u\n",
554                           kernel.langVersion[0], kernel.langVersion[1]);
555        output.write(buf, bufSize);
556    }
557    else // version not supplied
558        output.write("\"\n", 2);
559   
560    // print reqd_work_group_size: .cws XSIZE[,YSIZE[,ZSIZE]]
561    if (kernel.reqdWorkGroupSize[0] != 0 || kernel.reqdWorkGroupSize[1] != 0 ||
562        kernel.reqdWorkGroupSize[2] != 0)
563    {
564        bufSize = snprintf(buf, 100, "        .cws %u, %u, %u\n",
565               kernel.reqdWorkGroupSize[0], kernel.reqdWorkGroupSize[1],
566               kernel.reqdWorkGroupSize[2]);
567        output.write(buf, bufSize);
568    }
569   
570    // work group size hint
571    if (kernel.workGroupSizeHint[0] != 0 || kernel.workGroupSizeHint[1] != 0 ||
572        kernel.workGroupSizeHint[2] != 0)
573    {
574        bufSize = snprintf(buf, 100, "        .work_group_size_hint %u, %u, %u\n",
575               kernel.workGroupSizeHint[0], kernel.workGroupSizeHint[1],
576               kernel.workGroupSizeHint[2]);
577        output.write(buf, bufSize);
578    }
579    if (!kernel.vecTypeHint.empty())
580    {
581        output.write("        .vectypehint ", 21);
582        output.write(kernel.vecTypeHint.c_str(), kernel.vecTypeHint.size());
583        output.write("\n", 1);
584    }
585    if (!kernel.runtimeHandle.empty())
586    {
587        output.write("        .runtime_handle ", 24);
588        output.write(kernel.runtimeHandle.c_str(), kernel.runtimeHandle.size());
589        output.write("\n", 1);
590    }
591    if (hasValue(kernel.kernargSegmentSize))
592    {
593        bufSize = snprintf(buf, 100, "        .md_kernarg_segment_size %" PRIu64 "\n",
594                    kernel.kernargSegmentSize);
595        output.write(buf, bufSize);
596    }
597    if (hasValue(kernel.kernargSegmentAlign))
598    {
599        bufSize = snprintf(buf, 100, "        .md_kernarg_segment_align %" PRIu64 "\n",
600                    kernel.kernargSegmentAlign);
601        output.write(buf, bufSize);
602    }
603    if (hasValue(kernel.groupSegmentFixedSize))
604    {
605        bufSize = snprintf(buf, 100, "        .md_group_segment_fixed_size %" PRIu64 "\n",
606                    kernel.groupSegmentFixedSize);
607        output.write(buf, bufSize);
608    }
609    if (hasValue(kernel.privateSegmentFixedSize))
610    {
611        bufSize = snprintf(buf, 100, "        .md_private_segment_fixed_size %" PRIu64 "\n",
612                    kernel.privateSegmentFixedSize);
613        output.write(buf, bufSize);
614    }
615    if (hasValue(kernel.wavefrontSize))
616    {
617        bufSize = snprintf(buf, 100, "        .md_wavefront_size %u\n",
618                    kernel.wavefrontSize);
619        output.write(buf, bufSize);
620    }
621    if (hasValue(kernel.sgprsNum))
622    {
623        bufSize = snprintf(buf, 100, "        .md_sgprsnum %u\n", kernel.sgprsNum);
624        output.write(buf, bufSize);
625    }
626    if (hasValue(kernel.vgprsNum))
627    {
628        bufSize = snprintf(buf, 100, "        .md_vgprsnum %u\n", kernel.vgprsNum);
629        output.write(buf, bufSize);
630    }
631    if (hasValue(kernel.spilledSgprs))
632    {
633        bufSize = snprintf(buf, 100, "        .md_spilledsgprsnum %u\n",
634                           kernel.spilledSgprs);
635        output.write(buf, bufSize);
636    }
637    if (hasValue(kernel.spilledVgprs))
638    {
639        bufSize = snprintf(buf, 100, "        .md_spilledvgprsnum %u\n",
640                           kernel.spilledVgprs);
641        output.write(buf, bufSize);
642    }
643    if (hasValue(kernel.maxFlatWorkGroupSize))
644    {
645        bufSize = snprintf(buf, 100, "        .max_flat_work_group_size %" PRIu64 "\n",
646                    kernel.maxFlatWorkGroupSize);
647        output.write(buf, bufSize);
648    }
649    // fixed work group size
650    if (kernel.fixedWorkGroupSize[0] != 0 || kernel.fixedWorkGroupSize[1] != 0 ||
651        kernel.fixedWorkGroupSize[2] != 0)
652    {
653        bufSize = snprintf(buf, 100, "        .fixed_work_group_size %u, %u, %u\n",
654               kernel.fixedWorkGroupSize[0], kernel.fixedWorkGroupSize[1],
655               kernel.fixedWorkGroupSize[2]);
656        output.write(buf, bufSize);
657    }
658   
659    // dump kernel arguments
660    for (const ROCmKernelArgInfo& argInfo: kernel.argInfos)
661    {
662        output.write("        .arg ", 13);
663        if (!argInfo.name.empty())
664        {
665            output.write(argInfo.name.c_str(), argInfo.name.size());
666            output.write(", ", 2);
667        }
668        output.write("\"", 1);
669        std::string typeName = escapeStringCStyle(argInfo.typeName);
670        output.write(typeName.c_str(), typeName.size());
671        output.write("\", ", 3);
672        size_t bufSize = 0;
673        char buf[100];
674        bufSize = snprintf(buf, 100, "%" PRIu64 ", %" PRIu64,
675                           argInfo.size, argInfo.align);
676        output.write(buf, bufSize);
677        bufSize = snprintf(buf, 100, ", %s, %s", 
678                    disasmROCmValueKindNames[cxuint(argInfo.valueKind)],
679                    disasmROCmValueTypeNames[cxuint(argInfo.valueType)]);
680        output.write(buf, bufSize);
681       
682        if (argInfo.valueKind == ROCmValueKind::DYN_SHARED_PTR)
683        {
684            bufSize = snprintf(buf, 100, ", %" PRIu64, argInfo.pointeeAlign);
685            output.write(buf, bufSize);
686        }
687       
688        if (argInfo.valueKind == ROCmValueKind::DYN_SHARED_PTR ||
689            argInfo.valueKind == ROCmValueKind::GLOBAL_BUFFER)
690        {
691            bufSize = snprintf(buf, 100, ", %s",
692                    disasmROCmAddressSpaces[cxuint(argInfo.addressSpace)]);
693            output.write(buf, bufSize);
694        }
695       
696        if (argInfo.valueKind == ROCmValueKind::IMAGE ||
697            argInfo.valueKind == ROCmValueKind::PIPE)
698        {
699            bufSize = snprintf(buf, 100, ", %s",
700                    disasmROCmAccessQuals[cxuint(argInfo.accessQual)]);
701            output.write(buf, bufSize);
702        }
703        if (argInfo.valueKind == ROCmValueKind::GLOBAL_BUFFER ||
704            argInfo.valueKind == ROCmValueKind::IMAGE ||
705            argInfo.valueKind == ROCmValueKind::PIPE)
706        {
707            bufSize = snprintf(buf, 100, ", %s",
708                    disasmROCmAccessQuals[cxuint(argInfo.actualAccessQual)]);
709            output.write(buf, bufSize);
710        }
711       
712        if (argInfo.isConst)
713            output.write(" const", 6);
714        if (argInfo.isRestrict)
715            output.write(" restrict", 9);
716        if (argInfo.isVolatile)
717            output.write(" volatile", 9);
718        if (argInfo.isPipe)
719            output.write(" pipe", 5);
720       
721        output.write("\n", 1);
722    }
723}
724
725void CLRX::disassembleROCm(std::ostream& output, const ROCmDisasmInput* rocmInput,
726           ISADisassembler* isaDisassembler, Flags flags)
727{
728    const bool doMetadata = ((flags & (DISASM_METADATA|DISASM_CONFIG)) != 0);
729    const bool doDumpConfig = ((flags & DISASM_CONFIG) != 0);
730    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
731   
732    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(rocmInput->deviceType);
733    const cxuint maxSgprsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
734   
735    ROCmMetadata metadataInfo;
736    bool haveMetadataInfo = false;
737    if (doDumpConfig && rocmInput->metadata!=nullptr)
738    {
739        metadataInfo.parse(rocmInput->metadataSize, rocmInput->metadata);
740        haveMetadataInfo = true;
741    }
742   
743    {
744        // print AMD architecture version
745        char buf[40];
746        size_t size = snprintf(buf, 40, ".arch_minor %u\n", rocmInput->archMinor);
747        output.write(buf, size);
748        size = snprintf(buf, 40, ".arch_stepping %u\n", rocmInput->archStepping);
749        output.write(buf, size);
750    }
751   
752    if (rocmInput->eflags != 0)
753    {
754        // print eflags if not zero
755        char buf[40];
756        size_t size = snprintf(buf, 40, ".eflags %u\n", rocmInput->eflags);
757        output.write(buf, size);
758    }
759   
760    if (rocmInput->newBinFormat)
761        output.write(".newbinfmt\n", 11);
762   
763    if (!rocmInput->target.empty())
764    {
765        output.write(".target \"", 9);
766        const std::string escapedTarget = escapeStringCStyle(rocmInput->target);
767        output.write(escapedTarget.c_str(), escapedTarget.size());
768        output.write("\"\n", 2);
769    }
770   
771    if (doDumpData && rocmInput->globalData != nullptr &&
772        rocmInput->globalDataSize != 0)
773    {
774        output.write(".globaldata\n", 12);
775        output.write(".gdata:\n", 8); /// symbol used by text relocations
776        printDisasmData(rocmInput->globalDataSize, rocmInput->globalData, output);
777    }
778   
779    if (doMetadata && !doDumpConfig &&
780        rocmInput->metadataSize != 0 && rocmInput->metadata != nullptr)
781    {
782        output.write(".metadata\n", 10);
783        printDisasmLongString(rocmInput->metadataSize, rocmInput->metadata, output);
784    }
785   
786    Array<std::pair<CString, size_t> > sortedMdKernelIndices;
787   
788    if (doDumpConfig && haveMetadataInfo)
789    {
790        // main metadata info dump
791        char buf[100];
792        size_t bufSize;
793        if (metadataInfo.version[0] != BINGEN_NOTSUPPLIED)
794        {
795            bufSize = snprintf(buf, 100, ".md_version %u, %u\n", metadataInfo.version[0],
796                    metadataInfo.version[1]);
797            output.write(buf, bufSize);
798        }
799        for (const ROCmPrintfInfo& printfInfo: metadataInfo.printfInfos)
800        {
801            bufSize = snprintf(buf, 100, ".printf %u", printfInfo.id);
802            output.write(buf, bufSize);
803            for (uint32_t argSize: printfInfo.argSizes)
804            {
805                bufSize = snprintf(buf, 100, ", %u", argSize);
806                output.write(buf, bufSize);
807            }
808            output.write(", \"", 3);
809            std::string format = escapeStringCStyle(printfInfo.format);
810            output.write(format.c_str(), format.size());
811            output.write("\"\n", 2);
812        }
813        // prepare order of rocm metadata kernels
814        sortedMdKernelIndices.resize(metadataInfo.kernels.size());
815        for (size_t i = 0; i < sortedMdKernelIndices.size(); i++)
816            sortedMdKernelIndices[i] = std::make_pair(metadataInfo.kernels[i].name, i);
817        mapSort(sortedMdKernelIndices.begin(), sortedMdKernelIndices.end());
818    }
819   
820    // dump kernel config
821    for (const ROCmDisasmRegionInput& rinput: rocmInput->regions)
822        if (rinput.type != ROCmRegionType::DATA)
823        {
824            output.write(".kernel ", 8);
825            output.write(rinput.regionName.c_str(), rinput.regionName.size());
826            output.put('\n');
827            if (rinput.type == ROCmRegionType::FKERNEL)
828                output.write("    .fkernel\n", 13);
829            if (doDumpConfig)
830            {
831                dumpKernelConfig(output, maxSgprsNum, arch,
832                     *reinterpret_cast<const ROCmKernelConfig*>(
833                             rocmInput->code + rinput.offset));
834               
835                if (!haveMetadataInfo)
836                    continue; // no metatadata info
837                auto it = binaryMapFind(sortedMdKernelIndices.begin(),
838                        sortedMdKernelIndices.end(), rinput.regionName);
839                if (it == sortedMdKernelIndices.end())
840                    continue; // not found
841                // dump kernel metadata config
842                dumpKernelMetadataInfo(output, metadataInfo.kernels[it->second]);
843            }
844        }
845   
846    // disassembly code in HSA form
847    if (rocmInput->code != nullptr && rocmInput->codeSize != 0)
848        disassembleAMDHSACode(output, rocmInput->regions,
849                        rocmInput->codeSize, rocmInput->code, isaDisassembler, flags);
850}
Note: See TracBrowser for help on using the repository browser.