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

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

CLRadeonExtender: Use new methods to access to notes in DisasmROCm.

File size: 21.1 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cstdint>
22#include <cstdio>
23#include <inttypes.h>
24#include <string>
25#include <ostream>
26#include <memory>
27#include <vector>
28#include <utility>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/utils/MemAccess.h>
31#include <CLRX/amdbin/ROCmBinaries.h>
32#include <CLRX/amdasm/Disassembler.h>
33#include <CLRX/utils/GPUId.h>
34#include "DisasmInternals.h"
35
36using namespace CLRX;
37
38struct AMDGPUArchValues
39{
40    uint32_t major;
41    uint32_t minor;
42    uint32_t stepping;
43    GPUDeviceType deviceType;
44};
45
46static const AMDGPUArchValues amdGpuArchValuesTbl[] =
47{
48    { 0, 0, 0, GPUDeviceType::CAPE_VERDE },
49    { 7, 0, 0, GPUDeviceType::BONAIRE },
50    { 7, 0, 1, GPUDeviceType::HAWAII },
51    { 8, 0, 0, GPUDeviceType::ICELAND },
52    { 8, 0, 1, GPUDeviceType::CARRIZO },
53    { 8, 0, 2, GPUDeviceType::ICELAND },
54    { 8, 0, 3, GPUDeviceType::FIJI },
55    { 8, 0, 4, GPUDeviceType::FIJI },
56    { 8, 1, 0, GPUDeviceType::STONEY }
57};
58
59static const size_t amdGpuArchValuesNum = sizeof(amdGpuArchValuesTbl) /
60                sizeof(AMDGPUArchValues);
61
62ROCmDisasmInput* CLRX::getROCmDisasmInputFromBinary(const ROCmBinary& binary)
63{
64    std::unique_ptr<ROCmDisasmInput> input(new ROCmDisasmInput);
65    uint32_t archMajor = 0;
66    input->archMinor = 0;
67    input->archStepping = 0;
68   
69    {
70        const cxbyte* noteContent = (const cxbyte*)binary.getNotes();
71        if (noteContent==nullptr)
72            throw Exception("Missing notes in inner binary!");
73        size_t notesSize = binary.getNotesSize();
74        // find note about AMDGPU
75        for (size_t offset = 0; offset < notesSize; )
76        {
77            const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
78            size_t namesz = ULEV(nhdr->n_namesz);
79            size_t descsz = ULEV(nhdr->n_descsz);
80            if (usumGt(offset, namesz+descsz, notesSize))
81                throw Exception("Note offset+size out of range");
82            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
83                ::strcmp((const char*)noteContent+offset+sizeof(Elf64_Nhdr), "AMD")==0)
84            {    // AMDGPU type
85                const uint32_t* content = (const uint32_t*)
86                        (noteContent+offset+sizeof(Elf64_Nhdr) + 4);
87                archMajor = ULEV(content[1]);
88                input->archMinor = ULEV(content[2]);
89                input->archStepping = ULEV(content[3]);
90            }
91            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
92            offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
93        }
94    }
95    // determine device type
96    input->deviceType = GPUDeviceType::CAPE_VERDE;
97    if (archMajor==0)
98        input->deviceType = GPUDeviceType::CAPE_VERDE;
99    else if (archMajor==7)
100        input->deviceType = GPUDeviceType::BONAIRE;
101    else if (archMajor==8)
102        input->deviceType = GPUDeviceType::ICELAND;
103   
104    for (cxuint i = 0; i < amdGpuArchValuesNum; i++)
105        if (amdGpuArchValuesTbl[i].major==archMajor &&
106            amdGpuArchValuesTbl[i].minor==input->archMinor &&
107            amdGpuArchValuesTbl[i].stepping==input->archStepping)
108        {
109            input->deviceType = amdGpuArchValuesTbl[i].deviceType;
110            break;
111        }
112   
113    const size_t regionsNum = binary.getRegionsNum();
114    input->regions.resize(regionsNum);
115    size_t codeOffset = binary.getCode()-binary.getBinaryCode();
116    for (size_t i = 0; i < regionsNum; i++)
117    {
118        const ROCmRegion& region = binary.getRegion(i);
119        input->regions[i] = { region.regionName, size_t(region.size),
120            size_t(region.offset - codeOffset), region.isKernel };
121    }
122   
123    input->code = binary.getCode();
124    input->codeSize = binary.getCodeSize();
125    return input.release();
126}
127
128static void dumpKernelConfig(std::ostream& output, cxuint maxSgprsNum,
129             GPUArchitecture arch, const ROCmKernelConfig& config)
130{
131    output.write("    .config\n", 12);
132    // convert to native-endian
133    uint32_t amdCodeVersionMajor = ULEV(config.amdCodeVersionMajor);
134    uint32_t amdCodeVersionMinor = ULEV(config.amdCodeVersionMinor);
135    uint16_t amdMachineKind = ULEV(config.amdMachineKind);
136    uint16_t amdMachineMajor = ULEV(config.amdMachineMajor);
137    uint16_t amdMachineMinor = ULEV(config.amdMachineMinor);
138    uint16_t amdMachineStepping = ULEV(config.amdMachineStepping);
139    uint64_t kernelCodeEntryOffset = ULEV(config.kernelCodeEntryOffset);
140    uint64_t kernelCodePrefetchOffset = ULEV(config.kernelCodePrefetchOffset);
141    uint64_t kernelCodePrefetchSize = ULEV(config.kernelCodePrefetchSize);
142    uint64_t maxScrachBackingMemorySize = ULEV(config.maxScrachBackingMemorySize);
143    uint32_t computePgmRsrc1 = ULEV(config.computePgmRsrc1);
144    uint32_t computePgmRsrc2 = ULEV(config.computePgmRsrc2);
145    uint16_t enableSpgrRegisterFlags = ULEV(config.enableSpgrRegisterFlags);
146    uint16_t enableFeatureFlags = ULEV(config.enableFeatureFlags);
147    uint32_t workitemPrivateSegmentSize = ULEV(config.workitemPrivateSegmentSize);
148    uint32_t workgroupGroupSegmentSize = ULEV(config.workgroupGroupSegmentSize);
149    uint32_t gdsSegmentSize = ULEV(config.gdsSegmentSize);
150    uint64_t kernargSegmentSize = ULEV(config.kernargSegmentSize);
151    uint32_t workgroupFbarrierCount = ULEV(config.workgroupFbarrierCount);
152    uint16_t wavefrontSgprCount = ULEV(config.wavefrontSgprCount);
153    uint16_t workitemVgprCount = ULEV(config.workitemVgprCount);
154    uint16_t reservedVgprFirst = ULEV(config.reservedVgprFirst);
155    uint16_t reservedVgprCount = ULEV(config.reservedVgprCount);
156    uint16_t reservedSgprFirst = ULEV(config.reservedSgprFirst);
157    uint16_t reservedSgprCount = ULEV(config.reservedSgprCount);
158    uint16_t debugWavefrontPrivateSegmentOffsetSgpr =
159            ULEV(config.debugWavefrontPrivateSegmentOffsetSgpr);
160    uint16_t debugPrivateSegmentBufferSgpr = ULEV(config.debugPrivateSegmentBufferSgpr);
161    uint32_t callConvention = ULEV(config.callConvention);
162    uint64_t runtimeLoaderKernelSymbol = ULEV(config.runtimeLoaderKernelSymbol);
163   
164    size_t bufSize;
165    char buf[100];
166    const cxuint ldsShift = arch<GPUArchitecture::GCN1_1 ? 8 : 9;
167    const uint32_t pgmRsrc1 = computePgmRsrc1;
168    const uint32_t pgmRsrc2 = computePgmRsrc2;
169   
170    const cxuint dimMask = (pgmRsrc2 >> 7) & 7;
171    strcpy(buf, "        .dims ");
172    bufSize = 14;
173    if ((dimMask & 1) != 0)
174        buf[bufSize++] = 'x';
175    if ((dimMask & 2) != 0)
176        buf[bufSize++] = 'y';
177    if ((dimMask & 4) != 0)
178        buf[bufSize++] = 'z';
179    buf[bufSize++] = '\n';
180    output.write(buf, bufSize);
181   
182    bufSize = snprintf(buf, 100, "        .sgprsnum %u\n",
183              std::min((((pgmRsrc1>>6) & 0xf)<<3)+8, maxSgprsNum));
184    output.write(buf, bufSize);
185    bufSize = snprintf(buf, 100, "        .vgprsnum %u\n", ((pgmRsrc1 & 0x3f)<<2)+4);
186    output.write(buf, bufSize);
187    output.write(buf, bufSize);
188    if ((pgmRsrc1 & (1U<<20)) != 0)
189        output.write("        .privmode\n", 18);
190    if ((pgmRsrc1 & (1U<<22)) != 0)
191        output.write("        .debugmode\n", 19);
192    if ((pgmRsrc1 & (1U<<21)) != 0)
193        output.write("        .dx10clamp\n", 19);
194    if ((pgmRsrc1 & (1U<<23)) != 0)
195        output.write("        .ieeemode\n", 18);
196    if ((pgmRsrc2 & 0x400) != 0)
197        output.write("        .tgsize\n", 16);
198   
199    bufSize = snprintf(buf, 100, "        .floatmode 0x%02x\n", (pgmRsrc1>>12) & 0xff);
200    output.write(buf, bufSize);
201    bufSize = snprintf(buf, 100, "        .priority %u\n", (pgmRsrc1>>10) & 3);
202    output.write(buf, bufSize);
203    if (((pgmRsrc1>>24) & 0x7f) != 0)
204    {
205        bufSize = snprintf(buf, 100, "        .exceptions 0x%02x\n",
206                   (pgmRsrc1>>24) & 0x7f);
207        output.write(buf, bufSize);
208    }
209    const cxuint localSize = ((pgmRsrc2>>15) & 0x1ff) << ldsShift;
210    if (localSize!=0)
211    {
212        bufSize = snprintf(buf, 100, "        .localsize %u\n", localSize);
213        output.write(buf, bufSize);
214    }
215    bufSize = snprintf(buf, 100, "        .userdatanum %u\n", (pgmRsrc2>>1) & 0x1f);
216    output.write(buf, bufSize);
217   
218    bufSize = snprintf(buf, 100, "        .pgmrsrc1 0x%08x\n", pgmRsrc1);
219    output.write(buf, bufSize);
220    bufSize = snprintf(buf, 100, "        .pgmrsrc2 0x%08x\n", pgmRsrc2);
221    output.write(buf, bufSize);
222   
223    bufSize = snprintf(buf, 100, "        .codeversion %u, %u\n",
224                   amdCodeVersionMajor, amdCodeVersionMinor);
225    output.write(buf, bufSize);
226    bufSize = snprintf(buf, 100, "        .machine %hu, %hu, %hu, %hu\n",
227                   amdMachineKind, amdMachineMajor,
228                   amdMachineMinor, amdMachineStepping);
229    output.write(buf, bufSize);
230    bufSize = snprintf(buf, 100, "        .kernel_code_entry_offset 0x%" PRIx64 "\n",
231                       kernelCodeEntryOffset);
232    output.write(buf, bufSize);
233    if (kernelCodePrefetchOffset!=0)
234    {
235        bufSize = snprintf(buf, 100,
236                   "        .kernel_code_prefetch_offset 0x%" PRIx64 "\n",
237                           kernelCodePrefetchOffset);
238        output.write(buf, bufSize);
239    }
240    if (kernelCodePrefetchSize!=0)
241    {
242        bufSize = snprintf(buf, 100, "        .kernel_code_prefetch_size %" PRIu64 "\n",
243                           kernelCodePrefetchSize);
244        output.write(buf, bufSize);
245    }
246    if (maxScrachBackingMemorySize!=0)
247    {
248        bufSize = snprintf(buf, 100, "        .max_scratch_backing_memory %" PRIu64 "\n",
249                           maxScrachBackingMemorySize);
250        output.write(buf, bufSize);
251    }
252   
253    const uint16_t sgprFlags = enableSpgrRegisterFlags;
254    if ((sgprFlags&1) != 0)
255        output.write("        .use_private_segment_buffer\n", 36);
256    if ((sgprFlags&2) != 0)
257        output.write("        .use_dispatch_ptr\n", 26);
258    if ((sgprFlags&4) != 0)
259        output.write("        .use_queue_ptr\n", 24);
260    if ((sgprFlags&8) != 0)
261        output.write("        .use_kernarg_segment_ptr\n", 33);
262    if ((sgprFlags&16) != 0)
263        output.write("        .use_dispatch_id\n", 25);
264    if ((sgprFlags&32) != 0)
265        output.write("        .use_flat_scratch_init\n", 31);
266    if ((sgprFlags&64) != 0)
267        output.write("        .use_private_segment_size\n", 34);
268    if ((sgprFlags&128) != 0)
269        output.write("        .use_grid_workgroup_count_x\n", 36);
270    if ((sgprFlags&256) != 0)
271        output.write("        .use_grid_workgroup_count_y\n", 36);
272    if ((sgprFlags&512) != 0)
273        output.write("        .use_grid_workgroup_count_z\n", 36);
274    const uint16_t featureFlags = enableFeatureFlags;
275    if ((featureFlags&1) != 0)
276        output.write("        .use_ordered_append_gds\n", 32);
277    bufSize = snprintf(buf, 100, "        .private_elem_size %u\n",
278                       2U<<((featureFlags>>1)&3));
279    output.write(buf, bufSize);
280    if ((featureFlags&8) != 0)
281        output.write("        .use_ptr64\n", 19);
282    if ((featureFlags&16) != 0)
283        output.write("        .use_dynamic_call_stack\n", 32);
284    if ((featureFlags&32) != 0)
285        output.write("        .use_debug_enabled\n", 27);
286    if ((featureFlags&64) != 0)
287        output.write("        .use_xnack_enabled\n", 27);
288   
289    if (workitemPrivateSegmentSize!=0)
290    {
291        bufSize = snprintf(buf, 100, "        .workitem_private_segment_size %u\n",
292                         workitemPrivateSegmentSize);
293        output.write(buf, bufSize);
294    }
295    if (workgroupGroupSegmentSize!=0)
296    {
297        bufSize = snprintf(buf, 100, "        .workgroup_group_segment_size %u\n",
298                         workgroupGroupSegmentSize);
299        output.write(buf, bufSize);
300    }
301    if (gdsSegmentSize!=0)
302    {
303        bufSize = snprintf(buf, 100, "        .gds_segment_size %u\n",
304                         gdsSegmentSize);
305        output.write(buf, bufSize);
306    }
307    if (kernargSegmentSize!=0)
308    {
309        bufSize = snprintf(buf, 100, "        .kernarg_segment_size %" PRIu64 "\n",
310                         kernargSegmentSize);
311        output.write(buf, bufSize);
312    }
313    if (workgroupFbarrierCount!=0)
314    {
315        bufSize = snprintf(buf, 100, "        .workgroup_fbarrier_count %u\n",
316                         workgroupFbarrierCount);
317        output.write(buf, bufSize);
318    }
319    if (wavefrontSgprCount!=0)
320    {
321        bufSize = snprintf(buf, 100, "        .wavefront_sgpr_count %hu\n",
322                         wavefrontSgprCount);
323        output.write(buf, bufSize);
324    }
325    if (workitemVgprCount!=0)
326    {
327        bufSize = snprintf(buf, 100, "        .workitem_vgpr_count %hu\n",
328                         workitemVgprCount);
329        output.write(buf, bufSize);
330    }
331    if (reservedVgprFirst!=0)
332    {
333        bufSize = snprintf(buf, 100, "        .reserved_vgpr_first %hu\n",
334                         reservedVgprFirst);
335        output.write(buf, bufSize);
336    }
337    if (reservedVgprCount!=0)
338    {
339        bufSize = snprintf(buf, 100, "        .reserved_vgpr_count %hu\n",
340                         reservedVgprCount);
341        output.write(buf, bufSize);
342    }
343    if (reservedSgprFirst!=0)
344    {
345        bufSize = snprintf(buf, 100, "        .reserved_sgpr_first %hu\n",
346                         reservedSgprFirst);
347        output.write(buf, bufSize);
348    }
349    if (reservedSgprCount!=0)
350    {
351        bufSize = snprintf(buf, 100, "        .reserved_sgpr_count %hu\n",
352                         reservedSgprCount);
353        output.write(buf, bufSize);
354    }
355    if (debugWavefrontPrivateSegmentOffsetSgpr!=0)
356    {
357        bufSize = snprintf(buf, 100, "        "
358                        ".debug_wavefront_private_segment_offset_sgpr %hu\n",
359                         debugWavefrontPrivateSegmentOffsetSgpr);
360        output.write(buf, bufSize);
361    }
362    if (debugPrivateSegmentBufferSgpr!=0)
363    {
364        bufSize = snprintf(buf, 100, "        .debug_private_segment_buffer_sgpr %hu\n",
365                         debugPrivateSegmentBufferSgpr);
366        output.write(buf, bufSize);
367    }
368    bufSize = snprintf(buf, 100, "        .kernarg_segment_align %u\n",
369                     1U<<(config.kernargSegmentAlignment));
370    output.write(buf, bufSize);
371    bufSize = snprintf(buf, 100, "        .group_segment_align %u\n",
372                     1U<<(config.groupSegmentAlignment));
373    output.write(buf, bufSize);
374    bufSize = snprintf(buf, 100, "        .private_segment_align %u\n",
375                     1U<<(config.privateSegmentAlignment));
376    output.write(buf, bufSize);
377    bufSize = snprintf(buf, 100, "        .wavefront_size %u\n",
378                     1U<<(config.wavefrontSize));
379    output.write(buf, bufSize);
380    bufSize = snprintf(buf, 100, "        .call_convention 0x%x\n",
381                     callConvention);
382    output.write(buf, bufSize);
383    if (runtimeLoaderKernelSymbol!=0)
384    {
385        bufSize = snprintf(buf, 100,
386                   "        .runtime_loader_kernel_symbol 0x%" PRIx64 "\n",
387                         runtimeLoaderKernelSymbol);
388        output.write(buf, bufSize);
389    }
390    // new section, control_directive, outside .config
391    output.write("    .control_directive\n", 23);
392    printDisasmData(sizeof config.controlDirective, config.controlDirective, output, true);
393}
394
395void CLRX::disassembleROCm(std::ostream& output, const ROCmDisasmInput* rocmInput,
396           ISADisassembler* isaDisassembler, size_t& sectionCount, Flags flags)
397{
398    const bool doDumpData = ((flags & DISASM_DUMPDATA) != 0);
399    const bool doMetadata = ((flags & (DISASM_METADATA|DISASM_CONFIG)) != 0);
400    const bool doDumpCode = ((flags & DISASM_DUMPCODE) != 0);
401    const bool doDumpConfig = ((flags & DISASM_CONFIG) != 0);
402   
403    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(rocmInput->deviceType);
404    const cxuint maxSgprsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
405   
406    {
407        char buf[40];
408        size_t size = snprintf(buf, 40, ".arch_minor %u\n", rocmInput->archMinor);
409        output.write(buf, size);
410        size = snprintf(buf, 40, ".arch_stepping %u\n", rocmInput->archStepping);
411        output.write(buf, size);
412    }
413   
414    for (const ROCmDisasmRegionInput& rinput: rocmInput->regions)
415        if (rinput.isKernel)
416        {
417            output.write(".kernel ", 8);
418            output.write(rinput.regionName.c_str(), rinput.regionName.size());
419            output.put('\n');
420            if (doMetadata && doDumpConfig)
421                dumpKernelConfig(output, maxSgprsNum, arch,
422                     *reinterpret_cast<const ROCmKernelConfig*>(
423                             rocmInput->code + rinput.offset));
424        }
425   
426    const size_t regionsNum = rocmInput->regions.size();
427    typedef std::pair<size_t, size_t> SortEntry;
428    std::unique_ptr<SortEntry[]> sorted(new SortEntry[regionsNum]);
429    for (size_t i = 0; i < regionsNum; i++)
430        sorted[i] = std::make_pair(rocmInput->regions[i].offset, i);
431    mapSort(sorted.get(), sorted.get() + regionsNum);
432   
433    if (rocmInput->code != nullptr && rocmInput->codeSize != 0)
434    {
435        const cxbyte* code = rocmInput->code;
436        output.write(".text\n", 6);
437        // clear labels
438        isaDisassembler->clearNumberedLabels();
439       
440        /// analyze code with collecting labels
441        for (size_t i = 0; i < regionsNum; i++)
442        {
443            const ROCmDisasmRegionInput& region = rocmInput->regions[sorted[i].second];
444            if (region.isKernel && doDumpCode)
445            {
446                isaDisassembler->setInput(region.size-256, code + region.offset+256,
447                                    region.offset+256);
448                isaDisassembler->analyzeBeforeDisassemble();
449            }
450            isaDisassembler->addNamedLabel(region.offset, region.regionName);
451        }
452        isaDisassembler->prepareLabelsAndRelocations();
453       
454        ISADisassembler::LabelIter curLabel;
455        ISADisassembler::NamedLabelIter curNamedLabel;
456        const auto& labels = isaDisassembler->getLabels();
457        const auto& namedLabels = isaDisassembler->getNamedLabels();
458        // real disassemble
459        size_t prevRegionPos = 0;
460        for (size_t i = 0; i < regionsNum; i++)
461        {
462            const ROCmDisasmRegionInput& region = rocmInput->regions[sorted[i].second];
463            // set labelIters to previous position
464            isaDisassembler->setInput(prevRegionPos, code + region.offset,
465                                    region.offset, prevRegionPos);
466            curLabel = std::lower_bound(labels.begin(), labels.end(), prevRegionPos);
467            curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
468                std::make_pair(prevRegionPos, CString()),
469                  [](const std::pair<size_t,CString>& a,
470                                 const std::pair<size_t, CString>& b)
471                  { return a.first < b.first; });
472            isaDisassembler->writeLabelsToPosition(0, curLabel, curNamedLabel);
473            isaDisassembler->flushOutput();
474           
475            if (region.isKernel)
476            {
477                if (doMetadata)
478                {
479                    if (!doDumpConfig)
480                        printDisasmData(0x100, code + region.offset, output, true);
481                    else    // skip, config was dumped in kernel configuration
482                        output.write(".skip 256\n", 10);
483                }
484               
485                if (doDumpCode)
486                {
487                    isaDisassembler->setInput(region.size-256, code + region.offset+256,
488                                    region.offset+256, region.offset+1);
489                    isaDisassembler->setDontPrintLabels(i+1<regionsNum);
490                    isaDisassembler->disassemble();
491                }
492                /* previous position 1 byte after kernel region
493                 * labels at end will be printed by 'disassemble' */
494                prevRegionPos = region.offset + region.size + 1;
495            }
496            else if (doDumpData)
497            {
498                output.write(".global ", 8);
499                output.write(region.regionName.c_str(), region.regionName.size());
500                output.write("\n", 1);
501                printDisasmData(region.size, code + region.offset, output, true);
502                prevRegionPos = region.offset+1; // previous position byte after region
503            }
504        }
505       
506        if (regionsNum!=0 && !rocmInput->regions[sorted[regionsNum-1].second].isKernel)
507        {   // if last region is kernel, then print labels after last region
508            const ROCmDisasmRegionInput& region =
509                        rocmInput->regions[sorted[regionsNum-1].second];
510            isaDisassembler->writeLabelsToEnd(region.size, curLabel, curNamedLabel);
511            isaDisassembler->flushOutput();
512        }
513    }
514}
Note: See TracBrowser for help on using the repository browser.