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

Last change on this file since 3720 was 3720, checked in by matszpk, 3 years ago

CLRadeonExtender: DisasmROCm: Small optimizations in dumpKernelMetadataInfo.

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