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

Last change on this file since 3726 was 3726, checked in by matszpk, 19 months ago

CLRadeonExtender: DisasmAmd?&DisasmROCm: Check arg types and other fields before printing.
ROCmMetadata: Check arg types and other fields before generating. Escape number in string fields.
AsmROCm: Add additional pseudo-ops (only names) to set metadata info.

File size: 35.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 <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
517// helper for checking whether value is supplied
518static inline bool hasValue(cxuint value)
519{ return value!=BINGEN_NOTSUPPLIED && value!=BINGEN_DEFAULT; }
520
521static inline bool hasValue(uint64_t value)
522{ return value!=BINGEN64_NOTSUPPLIED && value!=BINGEN64_DEFAULT; }
523
524static const char* disasmROCmValueKindNames[] =
525{
526    "value", "globalbuf", "dynshptr", "sampler", "image", "pipe", "queue",
527    "gox", "goy", "goz", "none", "printfbuf", "defqueue", "complact"
528};
529
530static const char* disasmROCmValueTypeNames[] =
531{ "struct", "i8", "u8", "i16", "u16", "f16", "i32", "u32", "f32", "i64", "u64", "f64" };
532
533static const char* disasmROCmAddressSpaces[] =
534{ "none", "private", "global", "constant", "local", "generic", "region" };
535
536static const char* disasmROCmAccessQuals[] =
537{ "default", "read_only", "write_only", "read_write" };
538
539static void dumpKernelMetadataInfo(std::ostream& output, const ROCmKernelMetadata& kernel)
540{
541    output.write("    .config\n", 12);
542    output.write("        .md_symname ", 20);
543    output.write(kernel.symbolName.c_str(), kernel.symbolName.size());
544    output.write("\n", 1);
545    output.write("        .md_language \"", 22);
546    {
547        std::string langName = escapeStringCStyle(kernel.language);
548        output.write(langName.c_str(), langName.size());
549    }
550    size_t bufSize = 0;
551    char buf[100];
552    if (kernel.langVersion[0] != BINGEN_NOTSUPPLIED)
553    {
554        output.write("\", ", 3);
555        bufSize = snprintf(buf, 100, "%u, %u\n",
556                           kernel.langVersion[0], kernel.langVersion[1]);
557        output.write(buf, bufSize);
558    }
559    else // version not supplied
560        output.write("\"\n", 2);
561   
562    // print reqd_work_group_size: .cws XSIZE[,YSIZE[,ZSIZE]]
563    if (kernel.reqdWorkGroupSize[0] != 0 || kernel.reqdWorkGroupSize[1] != 0 ||
564        kernel.reqdWorkGroupSize[2] != 0)
565    {
566        bufSize = snprintf(buf, 100, "        .cws %u, %u, %u\n",
567               kernel.reqdWorkGroupSize[0], kernel.reqdWorkGroupSize[1],
568               kernel.reqdWorkGroupSize[2]);
569        output.write(buf, bufSize);
570    }
571   
572    // work group size hint
573    if (kernel.workGroupSizeHint[0] != 0 || kernel.workGroupSizeHint[1] != 0 ||
574        kernel.workGroupSizeHint[2] != 0)
575    {
576        bufSize = snprintf(buf, 100, "        .work_group_size_hint %u, %u, %u\n",
577               kernel.workGroupSizeHint[0], kernel.workGroupSizeHint[1],
578               kernel.workGroupSizeHint[2]);
579        output.write(buf, bufSize);
580    }
581    if (!kernel.vecTypeHint.empty())
582    {
583        output.write("        .vectypehint ", 21);
584        output.write(kernel.vecTypeHint.c_str(), kernel.vecTypeHint.size());
585        output.write("\n", 1);
586    }
587    if (!kernel.runtimeHandle.empty())
588    {
589        output.write("        .runtime_handle ", 24);
590        output.write(kernel.runtimeHandle.c_str(), kernel.runtimeHandle.size());
591        output.write("\n", 1);
592    }
593    if (hasValue(kernel.kernargSegmentSize))
594    {
595        bufSize = snprintf(buf, 100, "        .md_kernarg_segment_size %" PRIu64 "\n",
596                    kernel.kernargSegmentSize);
597        output.write(buf, bufSize);
598    }
599    if (hasValue(kernel.kernargSegmentAlign))
600    {
601        bufSize = snprintf(buf, 100, "        .md_kernarg_segment_align %" PRIu64 "\n",
602                    kernel.kernargSegmentAlign);
603        output.write(buf, bufSize);
604    }
605    if (hasValue(kernel.groupSegmentFixedSize))
606    {
607        bufSize = snprintf(buf, 100, "        .md_group_segment_fixed_size %" PRIu64 "\n",
608                    kernel.groupSegmentFixedSize);
609        output.write(buf, bufSize);
610    }
611    if (hasValue(kernel.privateSegmentFixedSize))
612    {
613        bufSize = snprintf(buf, 100, "        .md_private_segment_fixed_size %" PRIu64 "\n",
614                    kernel.privateSegmentFixedSize);
615        output.write(buf, bufSize);
616    }
617    if (hasValue(kernel.wavefrontSize))
618    {
619        bufSize = snprintf(buf, 100, "        .md_wavefront_size %u\n",
620                    kernel.wavefrontSize);
621        output.write(buf, bufSize);
622    }
623    // SGPRs and VGPRs
624    if (hasValue(kernel.sgprsNum))
625    {
626        bufSize = snprintf(buf, 100, "        .md_sgprsnum %u\n", kernel.sgprsNum);
627        output.write(buf, bufSize);
628    }
629    if (hasValue(kernel.vgprsNum))
630    {
631        bufSize = snprintf(buf, 100, "        .md_vgprsnum %u\n", kernel.vgprsNum);
632        output.write(buf, bufSize);
633    }
634    // spilled SGPRs and VGPRs
635    if (hasValue(kernel.spilledSgprs))
636    {
637        bufSize = snprintf(buf, 100, "        .md_spilledsgprs %u\n",
638                           kernel.spilledSgprs);
639        output.write(buf, bufSize);
640    }
641    if (hasValue(kernel.spilledVgprs))
642    {
643        bufSize = snprintf(buf, 100, "        .md_spilledvgprs %u\n",
644                           kernel.spilledVgprs);
645        output.write(buf, bufSize);
646    }
647    if (hasValue(kernel.maxFlatWorkGroupSize))
648    {
649        bufSize = snprintf(buf, 100, "        .max_flat_work_group_size %" PRIu64 "\n",
650                    kernel.maxFlatWorkGroupSize);
651        output.write(buf, bufSize);
652    }
653    // fixed work group size
654    if (kernel.fixedWorkGroupSize[0] != 0 || kernel.fixedWorkGroupSize[1] != 0 ||
655        kernel.fixedWorkGroupSize[2] != 0)
656    {
657        bufSize = snprintf(buf, 100, "        .fixed_work_group_size %u, %u, %u\n",
658               kernel.fixedWorkGroupSize[0], kernel.fixedWorkGroupSize[1],
659               kernel.fixedWorkGroupSize[2]);
660        output.write(buf, bufSize);
661    }
662   
663    // dump kernel arguments
664    for (const ROCmKernelArgInfo& argInfo: kernel.argInfos)
665    {
666        output.write("        .arg ", 13);
667        if (!argInfo.name.empty())
668        {
669            output.write(argInfo.name.c_str(), argInfo.name.size());
670            output.write(", ", 2);
671        }
672        output.write("\"", 1);
673        std::string typeName = escapeStringCStyle(argInfo.typeName);
674        output.write(typeName.c_str(), typeName.size());
675        output.write("\", ", 3);
676        size_t bufSize = 0;
677        char buf[100];
678        bufSize = snprintf(buf, 100, "%" PRIu64 ", %" PRIu64,
679                           argInfo.size, argInfo.align);
680        output.write(buf, bufSize);
681       
682        if (argInfo.valueKind > ROCmValueKind::MAX_VALUE)
683            throw DisasmException("Unknown argument value kind");
684        if (argInfo.valueType > ROCmValueType::MAX_VALUE)
685            throw DisasmException("Unknown argument value type");
686       
687        bufSize = snprintf(buf, 100, ", %s, %s", 
688                    disasmROCmValueKindNames[cxuint(argInfo.valueKind)],
689                    disasmROCmValueTypeNames[cxuint(argInfo.valueType)]);
690        output.write(buf, bufSize);
691       
692        if (argInfo.valueKind == ROCmValueKind::DYN_SHARED_PTR)
693        {
694            bufSize = snprintf(buf, 100, ", %" PRIu64, argInfo.pointeeAlign);
695            output.write(buf, bufSize);
696        }
697       
698        if (argInfo.valueKind == ROCmValueKind::DYN_SHARED_PTR ||
699            argInfo.valueKind == ROCmValueKind::GLOBAL_BUFFER)
700        {
701            if (argInfo.addressSpace > ROCmAddressSpace::MAX_VALUE)
702                throw DisasmException("Unknown address space");
703            buf[0] = ','; buf[1] = ' ';
704            const char* name = disasmROCmAddressSpaces[cxuint(argInfo.addressSpace)];
705            bufSize = strlen(name) + 2;
706            ::memcpy(buf+2, name, bufSize-2);
707            output.write(buf, bufSize);
708        }
709       
710        if (argInfo.valueKind == ROCmValueKind::IMAGE ||
711            argInfo.valueKind == ROCmValueKind::PIPE)
712        {
713            if (argInfo.accessQual > ROCmAccessQual::MAX_VALUE)
714                throw DisasmException("Unknown access qualifier");
715            buf[0] = ','; buf[1] = ' ';
716            const char* name = disasmROCmAccessQuals[cxuint(argInfo.accessQual)];
717            bufSize = strlen(name) + 2;
718            ::memcpy(buf+2, name, bufSize-2);
719            output.write(buf, bufSize);
720        }
721        if (argInfo.valueKind == ROCmValueKind::GLOBAL_BUFFER ||
722            argInfo.valueKind == ROCmValueKind::IMAGE ||
723            argInfo.valueKind == ROCmValueKind::PIPE)
724        {
725            if (argInfo.actualAccessQual > ROCmAccessQual::MAX_VALUE)
726                throw DisasmException("Unknown actual access qualifier");
727            buf[0] = ','; buf[1] = ' ';
728            const char* name = disasmROCmAccessQuals[cxuint(argInfo.actualAccessQual)];
729            bufSize = strlen(name) + 2;
730            ::memcpy(buf+2, name, bufSize-2);
731            output.write(buf, bufSize);
732        }
733       
734        if (argInfo.isConst)
735            output.write(" const", 6);
736        if (argInfo.isRestrict)
737            output.write(" restrict", 9);
738        if (argInfo.isVolatile)
739            output.write(" volatile", 9);
740        if (argInfo.isPipe)
741            output.write(" pipe", 5);
742       
743        output.write("\n", 1);
744    }
745}
746
747void CLRX::disassembleROCm(std::ostream& output, const ROCmDisasmInput* rocmInput,
748           ISADisassembler* isaDisassembler, Flags flags)
749{
750    const bool doMetadata = ((flags & (DISASM_METADATA|DISASM_CONFIG)) != 0);
751    const bool doDumpConfig = ((flags & DISASM_CONFIG) != 0);
752    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
753   
754    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(rocmInput->deviceType);
755    const cxuint maxSgprsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
756   
757    ROCmMetadata metadataInfo;
758    bool haveMetadataInfo = false;
759    if (doDumpConfig && rocmInput->metadata!=nullptr)
760    {
761        metadataInfo.parse(rocmInput->metadataSize, rocmInput->metadata);
762        haveMetadataInfo = true;
763    }
764   
765    {
766        // print AMD architecture version
767        char buf[40];
768        size_t size = snprintf(buf, 40, ".arch_minor %u\n", rocmInput->archMinor);
769        output.write(buf, size);
770        size = snprintf(buf, 40, ".arch_stepping %u\n", rocmInput->archStepping);
771        output.write(buf, size);
772    }
773   
774    if (rocmInput->eflags != 0)
775    {
776        // print eflags if not zero
777        char buf[40];
778        size_t size = snprintf(buf, 40, ".eflags %u\n", rocmInput->eflags);
779        output.write(buf, size);
780    }
781   
782    if (rocmInput->newBinFormat)
783        output.write(".newbinfmt\n", 11);
784   
785    if (!rocmInput->target.empty())
786    {
787        output.write(".target \"", 9);
788        const std::string escapedTarget = escapeStringCStyle(rocmInput->target);
789        output.write(escapedTarget.c_str(), escapedTarget.size());
790        output.write("\"\n", 2);
791    }
792   
793    if (doDumpData && rocmInput->globalData != nullptr &&
794        rocmInput->globalDataSize != 0)
795    {
796        output.write(".globaldata\n", 12);
797        output.write(".gdata:\n", 8); /// symbol used by text relocations
798        printDisasmData(rocmInput->globalDataSize, rocmInput->globalData, output);
799    }
800   
801    if (doMetadata && !doDumpConfig &&
802        rocmInput->metadataSize != 0 && rocmInput->metadata != nullptr)
803    {
804        output.write(".metadata\n", 10);
805        printDisasmLongString(rocmInput->metadataSize, rocmInput->metadata, output);
806    }
807   
808    Array<std::pair<CString, size_t> > sortedMdKernelIndices;
809   
810    if (doDumpConfig && haveMetadataInfo)
811    {
812        // main metadata info dump
813        char buf[100];
814        size_t bufSize;
815        if (metadataInfo.version[0] != BINGEN_NOTSUPPLIED)
816        {
817            bufSize = snprintf(buf, 100, ".md_version %u, %u\n", metadataInfo.version[0],
818                    metadataInfo.version[1]);
819            output.write(buf, bufSize);
820        }
821        for (const ROCmPrintfInfo& printfInfo: metadataInfo.printfInfos)
822        {
823            bufSize = snprintf(buf, 100, ".printf %u", printfInfo.id);
824            output.write(buf, bufSize);
825            for (uint32_t argSize: printfInfo.argSizes)
826            {
827                bufSize = snprintf(buf, 100, ", %u", argSize);
828                output.write(buf, bufSize);
829            }
830            output.write(", \"", 3);
831            std::string format = escapeStringCStyle(printfInfo.format);
832            output.write(format.c_str(), format.size());
833            output.write("\"\n", 2);
834        }
835        // prepare order of rocm metadata kernels
836        sortedMdKernelIndices.resize(metadataInfo.kernels.size());
837        for (size_t i = 0; i < sortedMdKernelIndices.size(); i++)
838            sortedMdKernelIndices[i] = std::make_pair(metadataInfo.kernels[i].name, i);
839        mapSort(sortedMdKernelIndices.begin(), sortedMdKernelIndices.end());
840    }
841   
842    // dump kernel config
843    for (const ROCmDisasmRegionInput& rinput: rocmInput->regions)
844        if (rinput.type != ROCmRegionType::DATA)
845        {
846            output.write(".kernel ", 8);
847            output.write(rinput.regionName.c_str(), rinput.regionName.size());
848            output.put('\n');
849            if (rinput.type == ROCmRegionType::FKERNEL)
850                output.write("    .fkernel\n", 13);
851            if (doDumpConfig)
852            {
853                dumpKernelConfig(output, maxSgprsNum, arch,
854                     *reinterpret_cast<const ROCmKernelConfig*>(
855                             rocmInput->code + rinput.offset));
856               
857                if (!haveMetadataInfo)
858                    continue; // no metatadata info
859                auto it = binaryMapFind(sortedMdKernelIndices.begin(),
860                        sortedMdKernelIndices.end(), rinput.regionName);
861                if (it == sortedMdKernelIndices.end())
862                    continue; // not found
863                // dump kernel metadata config
864                dumpKernelMetadataInfo(output, metadataInfo.kernels[it->second]);
865            }
866        }
867   
868    // disassembly code in HSA form
869    if (rocmInput->code != nullptr && rocmInput->codeSize != 0)
870        disassembleAMDHSACode(output, rocmInput->regions,
871                        rocmInput->codeSize, rocmInput->code, isaDisassembler, flags);
872}
Note: See TracBrowser for help on using the repository browser.