source: CLRX/CLRadeonExtender/trunk/amdasm/AsmROCmFormat.cpp @ 3443

Last change on this file since 3443 was 3443, checked in by matszpk, 21 months ago

CLRadeonExtender: Move tables with arch values (arch versions) to GPUId.

File size: 66.7 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2017 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 <cstdio>
22#include <cstring>
23#include <string>
24#include <vector>
25#include <unordered_set>
26#include <utility>
27#include <algorithm>
28#include <CLRX/utils/Utilities.h>
29#include <CLRX/amdasm/Assembler.h>
30#include <CLRX/amdasm/AsmFormats.h>
31#include "AsmROCmInternals.h"
32
33using namespace CLRX;
34
35// all ROCm pseudo-op names (sorted)
36static const char* rocmPseudoOpNamesTbl[] =
37{
38    "arch_minor", "arch_stepping",
39    "call_convention", "codeversion", "config",
40    "control_directive", "debug_private_segment_buffer_sgpr",
41    "debug_wavefront_private_segment_offset_sgpr",
42    "debugmode", "default_hsa_features", "dims", "dx10clamp",
43    "exceptions", "fkernel", "floatmode", "gds_segment_size",
44    "group_segment_align", "ieeemode", "kcode",
45    "kcodeend", "kernarg_segment_align",
46    "kernarg_segment_size", "kernel_code_entry_offset",
47    "kernel_code_prefetch_offset", "kernel_code_prefetch_size",
48    "localsize", "machine", "max_scratch_backing_memory",
49    "pgmrsrc1", "pgmrsrc2", "priority",
50    "private_elem_size", "private_segment_align",
51    "privmode", "reserved_sgprs", "reserved_vgprs",
52    "runtime_loader_kernel_symbol",
53    "scratchbuffer", "sgprsnum", "tgsize",
54    "use_debug_enabled", "use_dispatch_id",
55    "use_dispatch_ptr", "use_dynamic_call_stack",
56    "use_flat_scratch_init", "use_grid_workgroup_count",
57    "use_kernarg_segment_ptr", "use_ordered_append_gds",
58    "use_private_segment_buffer", "use_private_segment_size",
59    "use_ptr64", "use_queue_ptr", "use_xnack_enabled",
60    "userdatanum", "vgprsnum", "wavefront_sgpr_count",
61    "wavefront_size",  "workgroup_fbarrier_count",
62    "workgroup_group_segment_size", "workitem_private_segment_size",
63    "workitem_vgpr_count"
64};
65
66// all enums for ROCm pseudo-ops
67enum
68{
69    ROCMOP_ARCH_MINOR, ROCMOP_ARCH_STEPPING,
70    ROCMOP_CALL_CONVENTION, ROCMOP_CODEVERSION, ROCMOP_CONFIG,
71    ROCMOP_CONTROL_DIRECTIVE, ROCMOP_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR,
72    ROCMOP_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR,
73    ROCMOP_DEBUGMODE, ROCMOP_DEFAULT_HSA_FEATURES, ROCMOP_DIMS, ROCMOP_DX10CLAMP,
74    ROCMOP_EXCEPTIONS, ROCMOP_FKERNEL, ROCMOP_FLOATMODE, ROCMOP_GDS_SEGMENT_SIZE,
75    ROCMOP_GROUP_SEGMENT_ALIGN, ROCMOP_IEEEMODE, ROCMOP_KCODE,
76    ROCMOP_KCODEEND, ROCMOP_KERNARG_SEGMENT_ALIGN,
77    ROCMOP_KERNARG_SEGMENT_SIZE, ROCMOP_KERNEL_CODE_ENTRY_OFFSET,
78    ROCMOP_KERNEL_CODE_PREFETCH_OFFSET, ROCMOP_KERNEL_CODE_PREFETCH_SIZE,
79    ROCMOP_LOCALSIZE, ROCMOP_MACHINE, ROCMOP_MAX_SCRATCH_BACKING_MEMORY,
80    ROCMOP_PGMRSRC1, ROCMOP_PGMRSRC2, ROCMOP_PRIORITY,
81    ROCMOP_PRIVATE_ELEM_SIZE, ROCMOP_PRIVATE_SEGMENT_ALIGN,
82    ROCMOP_PRIVMODE, ROCMOP_RESERVED_SGPRS, ROCMOP_RESERVED_VGPRS,
83    ROCMOP_RUNTIME_LOADER_KERNEL_SYMBOL,
84    ROCMOP_SCRATCHBUFFER, ROCMOP_SGPRSNUM, ROCMOP_TGSIZE,
85    ROCMOP_USE_DEBUG_ENABLED, ROCMOP_USE_DISPATCH_ID,
86    ROCMOP_USE_DISPATCH_PTR, ROCMOP_USE_DYNAMIC_CALL_STACK,
87    ROCMOP_USE_FLAT_SCRATCH_INIT, ROCMOP_USE_GRID_WORKGROUP_COUNT,
88    ROCMOP_USE_KERNARG_SEGMENT_PTR, ROCMOP_USE_ORDERED_APPEND_GDS,
89    ROCMOP_USE_PRIVATE_SEGMENT_BUFFER, ROCMOP_USE_PRIVATE_SEGMENT_SIZE,
90    ROCMOP_USE_PTR64, ROCMOP_USE_QUEUE_PTR, ROCMOP_USE_XNACK_ENABLED,
91    ROCMOP_USERDATANUM, ROCMOP_VGPRSNUM, ROCMOP_WAVEFRONT_SGPR_COUNT,
92    ROCMOP_WAVEFRONT_SIZE, ROCMOP_WORKGROUP_FBARRIER_COUNT,
93    ROCMOP_WORKGROUP_GROUP_SEGMENT_SIZE, ROCMOP_WORKITEM_PRIVATE_SEGMENT_SIZE,
94    ROCMOP_WORKITEM_VGPR_COUNT
95};
96
97/*
98 * ROCm format handler
99 */
100
101AsmROCmHandler::AsmROCmHandler(Assembler& assembler): AsmFormatHandler(assembler),
102             output{}, codeSection(0), commentSection(ASMSECT_NONE),
103             extraSectionCount(0)
104{
105    output.archMinor = output.archStepping = UINT32_MAX;
106    assembler.currentKernel = ASMKERN_GLOBAL;
107    assembler.currentSection = 0;
108    // add text section as first
109    sections.push_back({ ASMKERN_GLOBAL, AsmSectionType::CODE,
110                ELFSECTID_TEXT, ".text" });
111    currentKcodeKernel = ASMKERN_GLOBAL;
112    savedSection = 0;
113}
114
115AsmROCmHandler::~AsmROCmHandler()
116{
117    for (Kernel* kernel: kernelStates)
118        delete kernel;
119}
120
121cxuint AsmROCmHandler::addKernel(const char* kernelName)
122{
123    cxuint thisKernel = output.symbols.size();
124    cxuint thisSection = sections.size();
125    output.addEmptyKernel(kernelName);
126    /// add kernel config section
127    sections.push_back({ thisKernel, AsmSectionType::CONFIG, ELFSECTID_UNDEF, nullptr });
128    kernelStates.push_back(
129        new Kernel{ thisSection, nullptr, false, ASMSECT_NONE, thisSection });
130   
131    if (assembler.currentKernel == ASMKERN_GLOBAL)
132        savedSection = assembler.currentSection;
133   
134    assembler.currentKernel = thisKernel;
135    assembler.currentSection = thisSection;
136    return thisKernel;
137}
138
139cxuint AsmROCmHandler::addSection(const char* sectionName, cxuint kernelId)
140{
141    const cxuint thisSection = sections.size();
142    Section section;
143    section.kernelId = ASMKERN_GLOBAL;  // we ignore input kernelId, we go to main
144       
145    if (::strcmp(sectionName, ".text") == 0)
146    {
147         // code section
148        if (codeSection!=ASMSECT_NONE)
149            throw AsmFormatException("Only one section '.text' can be in binary");
150        codeSection = thisSection;
151        section.type = AsmSectionType::CODE;
152        section.elfBinSectId = ELFSECTID_TEXT;
153        section.name = ".text"; // set static name (available by whole lifecycle)
154    }
155    else if (::strcmp(sectionName, ".comment") == 0)
156    {
157         // comment section
158        if (commentSection!=ASMSECT_NONE)
159            throw AsmFormatException("Only one section '.comment' can be in binary");
160        commentSection = thisSection;
161        section.type = AsmSectionType::ROCM_COMMENT;
162        section.elfBinSectId = ELFSECTID_COMMENT;
163        section.name = ".comment"; // set static name (available by whole lifecycle)
164    }
165    else
166    {
167        // extra (user) section
168        auto out = extraSectionMap.insert(std::make_pair(CString(sectionName),
169                    thisSection));
170        if (!out.second)
171            throw AsmFormatException("Section already exists");
172        section.type = AsmSectionType::EXTRA_SECTION;
173        section.elfBinSectId = extraSectionCount++;
174        /// reference entry is available and unchangeable by whole lifecycle of section map
175        section.name = out.first->first.c_str();
176    }
177    sections.push_back(section);
178   
179    assembler.currentKernel = ASMKERN_GLOBAL;
180    assembler.currentSection = thisSection;
181    return thisSection;
182}
183
184cxuint AsmROCmHandler::getSectionId(const char* sectionName) const
185{
186    if (::strcmp(sectionName, ".text") == 0) // code
187        return codeSection;
188    else if (::strcmp(sectionName, ".comment") == 0) // comment
189        return commentSection;
190    else
191    {
192        // if extra section, then find it
193        SectionMap::const_iterator it = extraSectionMap.find(sectionName);
194        if (it != extraSectionMap.end())
195            return it->second;
196    }
197    return ASMSECT_NONE;
198}
199
200void AsmROCmHandler::setCurrentKernel(cxuint kernel)
201{
202    if (kernel != ASMKERN_GLOBAL && kernel >= kernelStates.size())
203        throw AsmFormatException("KernelId out of range");
204   
205    if (assembler.currentKernel == ASMKERN_GLOBAL)
206        savedSection = assembler.currentSection;
207    else // if kernel
208        kernelStates[assembler.currentKernel]->savedSection = assembler.currentSection;
209   
210    assembler.currentKernel = kernel;
211    if (kernel != ASMKERN_GLOBAL)
212        assembler.currentSection = kernelStates[kernel]->savedSection;
213    else // default main section
214        assembler.currentSection = savedSection;
215}
216
217void AsmROCmHandler::setCurrentSection(cxuint sectionId)
218{
219    if (sectionId >= sections.size())
220        throw AsmFormatException("SectionId out of range");
221   
222    if (assembler.currentKernel == ASMKERN_GLOBAL)
223        savedSection = assembler.currentSection;
224    else // if kernel
225        kernelStates[assembler.currentKernel]->savedSection = assembler.currentSection;
226   
227    assembler.currentSection = sectionId;
228    assembler.currentKernel = sections[sectionId].kernelId;
229}
230
231
232AsmFormatHandler::SectionInfo AsmROCmHandler::getSectionInfo(cxuint sectionId) const
233{
234    if (sectionId >= sections.size())
235        throw AsmFormatException("Section doesn't exists");
236   
237    AsmFormatHandler::SectionInfo info;
238    info.type = sections[sectionId].type;
239    info.flags = 0;
240    // code is addressable and writeable
241    if (info.type == AsmSectionType::CODE)
242        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE;
243    // any other section (except config) are absolute addressable and writeable
244    else if (info.type != AsmSectionType::CONFIG)
245        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE | ASMSECT_ABS_ADDRESSABLE;
246   
247    info.name = sections[sectionId].name;
248    return info;
249}
250
251void AsmROCmHandler::restoreKcodeCurrentAllocRegs()
252{
253    if (currentKcodeKernel != ASMKERN_GLOBAL)
254    {
255        Kernel& newKernel = *kernelStates[currentKcodeKernel];
256        assembler.isaAssembler->setAllocatedRegisters(newKernel.allocRegs,
257                            newKernel.allocRegFlags);
258    }
259}
260
261void AsmROCmHandler::saveKcodeCurrentAllocRegs()
262{
263    if (currentKcodeKernel != ASMKERN_GLOBAL)
264    {
265        // save other state
266        size_t regTypesNum;
267        Kernel& oldKernel = *kernelStates[currentKcodeKernel];
268        const cxuint* regs = assembler.isaAssembler->getAllocatedRegisters(
269                            regTypesNum, oldKernel.allocRegFlags);
270        std::copy(regs, regs+regTypesNum, oldKernel.allocRegs);
271    }
272}
273
274
275void AsmROCmHandler::handleLabel(const CString& label)
276{
277    if (assembler.sections[assembler.currentSection].type != AsmSectionType::CODE)
278        return;
279    auto kit = assembler.kernelMap.find(label);
280    if (kit == assembler.kernelMap.end())
281        return;
282    if (!kcodeSelection.empty())
283        return; // do not change if inside kcode
284    // add code start
285    assembler.sections[assembler.currentSection].addCodeFlowEntry({
286                    size_t(assembler.currentOutPos), 0, AsmCodeFlowType::START });
287    // save other state
288    saveKcodeCurrentAllocRegs();
289    if (currentKcodeKernel != ASMKERN_GLOBAL)
290        assembler.kernels[currentKcodeKernel].closeCodeRegion(
291                        assembler.sections[codeSection].content.size());
292    // restore this state
293    currentKcodeKernel = kit->second;
294    restoreKcodeCurrentAllocRegs();
295    if (currentKcodeKernel != ASMKERN_GLOBAL)
296        assembler.kernels[currentKcodeKernel].openCodeRegion(
297                        assembler.sections[codeSection].content.size());
298}
299
300void AsmROCmHandler::Kernel::initializeKernelConfig()
301{
302    if (!config)
303    {
304        config.reset(new AsmROCmKernelConfig{});
305        config->initialize();
306    }
307}
308
309namespace CLRX
310{
311
312bool AsmROCmPseudoOps::checkPseudoOpName(const CString& string)
313{
314    if (string.empty() || string[0] != '.')
315        return false;
316    const size_t pseudoOp = binaryFind(rocmPseudoOpNamesTbl, rocmPseudoOpNamesTbl +
317                sizeof(rocmPseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
318               CStringLess()) - rocmPseudoOpNamesTbl;
319    return pseudoOp < sizeof(rocmPseudoOpNamesTbl)/sizeof(char*);
320}
321
322void AsmROCmPseudoOps::setArchMinor(AsmROCmHandler& handler, const char* linePtr)
323{
324    Assembler& asmr = handler.assembler;
325    const char* end = asmr.line + asmr.lineSize;
326    skipSpacesToEnd(linePtr, end);
327    uint64_t value;
328    const char* valuePlace = linePtr;
329    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
330        return;
331    asmr.printWarningForRange(sizeof(cxuint)<<3, value,
332                 asmr.getSourcePos(valuePlace), WS_UNSIGNED);
333    if (!checkGarbagesAtEnd(asmr, linePtr))
334        return;
335    handler.output.archMinor = value;
336}
337
338void AsmROCmPseudoOps::setArchStepping(AsmROCmHandler& handler, const char* linePtr)
339{
340    Assembler& asmr = handler.assembler;
341    const char* end = asmr.line + asmr.lineSize;
342    skipSpacesToEnd(linePtr, end);
343    uint64_t value;
344    const char* valuePlace = linePtr;
345    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
346        return;
347    asmr.printWarningForRange(sizeof(cxuint)<<3, value,
348                 asmr.getSourcePos(valuePlace), WS_UNSIGNED);
349    if (!checkGarbagesAtEnd(asmr, linePtr))
350        return;
351    handler.output.archStepping = value;
352}
353
354   
355void AsmROCmPseudoOps::doConfig(AsmROCmHandler& handler, const char* pseudoOpPlace,
356                  const char* linePtr)
357{
358    Assembler& asmr = handler.assembler;
359    if (asmr.currentKernel==ASMKERN_GLOBAL)
360        PSEUDOOP_RETURN_BY_ERROR("Kernel config can be defined only inside kernel")
361   
362    if (!checkGarbagesAtEnd(asmr, linePtr))
363        return;
364    AsmROCmHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
365    asmr.goToSection(pseudoOpPlace, kernel.configSection);
366    kernel.initializeKernelConfig();
367}
368
369void AsmROCmPseudoOps::doControlDirective(AsmROCmHandler& handler,
370              const char* pseudoOpPlace, const char* linePtr)
371{
372    Assembler& asmr = handler.assembler;
373    if (asmr.currentKernel==ASMKERN_GLOBAL)
374        PSEUDOOP_RETURN_BY_ERROR("Kernel control directive can be defined "
375                    "only inside kernel")
376    if (!checkGarbagesAtEnd(asmr, linePtr))
377        return;
378   
379    AsmROCmHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
380    if (kernel.ctrlDirSection == ASMSECT_NONE)
381    {
382        // define control directive section (if not exists)
383        cxuint thisSection = handler.sections.size();
384        handler.sections.push_back({ asmr.currentKernel,
385            AsmSectionType::ROCM_CONFIG_CTRL_DIRECTIVE,
386            ELFSECTID_UNDEF, nullptr });
387        kernel.ctrlDirSection = thisSection;
388    }
389    asmr.goToSection(pseudoOpPlace, kernel.ctrlDirSection);
390    handler.kernelStates[asmr.currentKernel]->initializeKernelConfig();
391}
392
393void AsmROCmPseudoOps::doFKernel(AsmROCmHandler& handler, const char* pseudoOpPlace,
394                      const char* linePtr)
395{
396    Assembler& asmr = handler.assembler;
397    if (asmr.currentKernel==ASMKERN_GLOBAL)
398        PSEUDOOP_RETURN_BY_ERROR(".fkernel can be only inside kernel")
399    if (!checkGarbagesAtEnd(asmr, linePtr))
400        return;
401    // set fkernel flag for kernel
402    handler.kernelStates[asmr.currentKernel]->isFKernel = true;
403}
404
405bool AsmROCmPseudoOps::checkConfigValue(Assembler& asmr, const char* valuePlace,
406                ROCmConfigValueTarget target, uint64_t value)
407{
408    bool good = true;
409    switch(target)
410    {
411        case ROCMCVAL_SGPRSNUM:
412        {
413            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
414                        asmr.deviceType);
415            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
416            if (value > maxSGPRsNum)
417            {
418                char buf[64];
419                snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
420                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
421            }
422            break;
423        }
424        case ROCMCVAL_VGPRSNUM:
425        {
426            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
427                        asmr.deviceType);
428            cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
429            if (value > maxVGPRsNum)
430            {
431                char buf[64];
432                snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
433                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
434            }
435            break;
436        }
437        case ROCMCVAL_EXCEPTIONS:
438            asmr.printWarningForRange(7, value,
439                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
440            value &= 0x7f;
441            break;
442        case ROCMCVAL_FLOATMODE:
443            asmr.printWarningForRange(8, value,
444                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
445            value &= 0xff;
446            break;
447        case ROCMCVAL_PRIORITY:
448            asmr.printWarningForRange(2, value,
449                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
450            value &= 3;
451            break;
452        case ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE: // local size
453        {
454            asmr.printWarningForRange(32, value,
455                        asmr.getSourcePos(valuePlace), WS_UNSIGNED);
456           
457            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
458                        asmr.deviceType);
459            const cxuint maxLocalSize = getGPUMaxLocalSize(arch);
460            if (value > maxLocalSize)
461            {
462                char buf[64];
463                snprintf(buf, 64, "LocalSize out of range (0-%u)", maxLocalSize);
464                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
465            }
466            break;
467        }
468        case ROCMCVAL_USERDATANUM:
469            if (value > 16)
470                ASM_NOTGOOD_BY_ERROR(valuePlace, "UserDataNum out of range (0-16)")
471            break;
472        case ROCMCVAL_PRIVATE_ELEM_SIZE:
473            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
474                ASM_NOTGOOD_BY_ERROR(valuePlace,
475                                "Private element size must be power of two")
476            else if (value < 2 || value > 16)
477                ASM_NOTGOOD_BY_ERROR(valuePlace, "Private element size out of range")
478            break;
479        case ROCMCVAL_KERNARG_SEGMENT_ALIGN:
480        case ROCMCVAL_GROUP_SEGMENT_ALIGN:
481        case ROCMCVAL_PRIVATE_SEGMENT_ALIGN:
482            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
483                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment must be power of two")
484            else if (value < 16)
485                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment must be not smaller than 16")
486            break;
487        case ROCMCVAL_WAVEFRONT_SIZE:
488            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
489                ASM_NOTGOOD_BY_ERROR(valuePlace, "Wavefront size must be power of two")
490            else if (value > 256)
491                ASM_NOTGOOD_BY_ERROR(valuePlace,
492                            "Wavefront size must be not greater than 256")
493            break;
494        case ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE:
495        case ROCMCVAL_GDS_SEGMENT_SIZE:
496        case ROCMCVAL_WORKGROUP_FBARRIER_COUNT:
497        case ROCMCVAL_CALL_CONVENTION:
498        case ROCMCVAL_PGMRSRC1:
499        case ROCMCVAL_PGMRSRC2:
500            asmr.printWarningForRange(32, value,
501                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
502            break;
503        case ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
504        case ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
505        {
506            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
507                        asmr.deviceType);
508            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
509            if (value >= maxSGPRsNum)
510                ASM_NOTGOOD_BY_ERROR(valuePlace, "SGPR register out of range")
511            break;
512        }
513        default:
514            break;
515    }
516    return good;
517}
518
519void AsmROCmPseudoOps::setConfigValueMain(AsmAmdHsaKernelConfig& config,
520                ROCmConfigValueTarget target, uint64_t value)
521{
522    switch(target)
523    {
524        case ROCMCVAL_SGPRSNUM:
525            config.usedSGPRsNum = value;
526            break;
527        case ROCMCVAL_VGPRSNUM:
528            config.usedVGPRsNum = value;
529            break;
530        case ROCMCVAL_PGMRSRC1:
531            config.computePgmRsrc1 = value;
532            break;
533        case ROCMCVAL_PGMRSRC2:
534            config.computePgmRsrc2 = value;
535            break;
536        case ROCMCVAL_FLOATMODE:
537            config.floatMode = value;
538            break;
539        case ROCMCVAL_PRIORITY:
540            config.priority = value;
541            break;
542        case ROCMCVAL_USERDATANUM:
543            config.userDataNum = value;
544            break;
545        case ROCMCVAL_EXCEPTIONS:
546            config.exceptions = value;
547            break;
548        case ROCMCVAL_KERNEL_CODE_ENTRY_OFFSET:
549            config.kernelCodeEntryOffset = value;
550            break;
551        case ROCMCVAL_KERNEL_CODE_PREFETCH_OFFSET:
552            config.kernelCodePrefetchOffset = value;
553            break;
554        case ROCMCVAL_KERNEL_CODE_PREFETCH_SIZE:
555            config.kernelCodePrefetchSize = value;
556            break;
557        case ROCMCVAL_MAX_SCRATCH_BACKING_MEMORY:
558            config.maxScrachBackingMemorySize = value;
559            break;
560        case ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE:
561            config.workitemPrivateSegmentSize = value;
562            break;
563        case ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE:
564            config.workgroupGroupSegmentSize = value;
565            break;
566        case ROCMCVAL_GDS_SEGMENT_SIZE:
567            config.gdsSegmentSize = value;
568            break;
569        case ROCMCVAL_KERNARG_SEGMENT_SIZE:
570            config.kernargSegmentSize = value;
571            break;
572        case ROCMCVAL_WORKGROUP_FBARRIER_COUNT:
573            config.workgroupFbarrierCount = value;
574            break;
575        case ROCMCVAL_WAVEFRONT_SGPR_COUNT:
576            config.wavefrontSgprCount = value;
577            break;
578        case ROCMCVAL_WORKITEM_VGPR_COUNT:
579            config.workitemVgprCount = value;
580            break;
581        case ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
582            config.debugWavefrontPrivateSegmentOffsetSgpr = value;
583            break;
584        case ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
585            config.debugPrivateSegmentBufferSgpr = value;
586            break;
587        case ROCMCVAL_PRIVATE_ELEM_SIZE:
588            config.enableFeatureFlags = (config.enableFeatureFlags & ~6) |
589                    ((63-CLZ64(value)-1)<<1);
590            break;
591        case ROCMCVAL_KERNARG_SEGMENT_ALIGN:
592            config.kernargSegmentAlignment = 63-CLZ64(value);
593            break;
594        case ROCMCVAL_GROUP_SEGMENT_ALIGN:
595            config.groupSegmentAlignment = 63-CLZ64(value);
596            break;
597        case ROCMCVAL_PRIVATE_SEGMENT_ALIGN:
598            config.privateSegmentAlignment = 63-CLZ64(value);
599            break;
600        case ROCMCVAL_WAVEFRONT_SIZE:
601            config.wavefrontSize = 63-CLZ64(value);
602            break;
603        case ROCMCVAL_CALL_CONVENTION:
604            config.callConvention = value;
605            break;
606        case ROCMCVAL_RUNTIME_LOADER_KERNEL_SYMBOL:
607            config.runtimeLoaderKernelSymbol = value;
608            break;
609        default:
610            break;
611    }
612}
613
614void AsmROCmPseudoOps::setConfigValue(AsmROCmHandler& handler, const char* pseudoOpPlace,
615                  const char* linePtr, ROCmConfigValueTarget target)
616{
617    Assembler& asmr = handler.assembler;
618    const char* end = asmr.line + asmr.lineSize;
619   
620    if (asmr.currentKernel==ASMKERN_GLOBAL ||
621        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
622        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
623   
624    skipSpacesToEnd(linePtr, end);
625    const char* valuePlace = linePtr;
626    uint64_t value = BINGEN64_NOTSUPPLIED;
627    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
628    /* ranges checking */
629    if (good)
630        good = checkConfigValue(asmr, valuePlace, target, value);
631    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
632        return;
633   
634    AsmROCmKernelConfig& config = *(handler.kernelStates[asmr.currentKernel]->config);
635    // set value
636    setConfigValueMain(config, target, value);
637}
638
639void AsmROCmPseudoOps::setConfigBoolValueMain(AsmAmdHsaKernelConfig& config,
640                ROCmConfigValueTarget target)
641{
642    switch(target)
643    {
644        case ROCMCVAL_PRIVMODE:
645            config.privilegedMode = true;
646            break;
647        case ROCMCVAL_DEBUGMODE:
648            config.debugMode = true;
649            break;
650        case ROCMCVAL_DX10CLAMP:
651            config.dx10Clamp = true;
652            break;
653        case ROCMCVAL_IEEEMODE:
654            config.ieeeMode = true;
655            break;
656        case ROCMCVAL_TGSIZE:
657            config.tgSize = true;
658            break;
659        case ROCMCVAL_USE_PRIVATE_SEGMENT_BUFFER:
660            config.enableSgprRegisterFlags |= ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER;
661            break;
662        case ROCMCVAL_USE_DISPATCH_PTR:
663            config.enableSgprRegisterFlags |= ROCMFLAG_USE_DISPATCH_PTR;
664            break;
665        case ROCMCVAL_USE_QUEUE_PTR:
666            config.enableSgprRegisterFlags |= ROCMFLAG_USE_QUEUE_PTR;
667            break;
668        case ROCMCVAL_USE_KERNARG_SEGMENT_PTR:
669            config.enableSgprRegisterFlags |= ROCMFLAG_USE_KERNARG_SEGMENT_PTR;
670            break;
671        case ROCMCVAL_USE_DISPATCH_ID:
672            config.enableSgprRegisterFlags |= ROCMFLAG_USE_DISPATCH_ID;
673            break;
674        case ROCMCVAL_USE_FLAT_SCRATCH_INIT:
675            config.enableSgprRegisterFlags |= ROCMFLAG_USE_FLAT_SCRATCH_INIT;
676            break;
677        case ROCMCVAL_USE_PRIVATE_SEGMENT_SIZE:
678            config.enableSgprRegisterFlags |= ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE;
679            break;
680        case ROCMCVAL_USE_ORDERED_APPEND_GDS:
681            config.enableFeatureFlags |= ROCMFLAG_USE_ORDERED_APPEND_GDS;
682            break;
683        case ROCMCVAL_USE_PTR64:
684            config.enableFeatureFlags |= ROCMFLAG_USE_PTR64;
685            break;
686        case ROCMCVAL_USE_DYNAMIC_CALL_STACK:
687            config.enableFeatureFlags |= ROCMFLAG_USE_DYNAMIC_CALL_STACK;
688            break;
689        case ROCMCVAL_USE_DEBUG_ENABLED:
690            config.enableFeatureFlags |= ROCMFLAG_USE_DEBUG_ENABLED;
691            break;
692        case ROCMCVAL_USE_XNACK_ENABLED:
693            config.enableFeatureFlags |= ROCMFLAG_USE_XNACK_ENABLED;
694            break;
695        default:
696            break;
697    }
698}
699
700void AsmROCmPseudoOps::setConfigBoolValue(AsmROCmHandler& handler,
701          const char* pseudoOpPlace, const char* linePtr, ROCmConfigValueTarget target)
702{
703    Assembler& asmr = handler.assembler;
704    const char* end = asmr.line + asmr.lineSize;
705   
706    if (asmr.currentKernel==ASMKERN_GLOBAL ||
707        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
708        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
709   
710    skipSpacesToEnd(linePtr, end);
711    if (!checkGarbagesAtEnd(asmr, linePtr))
712        return;
713   
714    AsmROCmKernelConfig& config = *(handler.kernelStates[asmr.currentKernel]->config);
715   
716    setConfigBoolValueMain(config, target);
717}
718
719void AsmROCmPseudoOps::setDefaultHSAFeatures(AsmROCmHandler& handler,
720                    const char* pseudoOpPlace, const char* linePtr)
721{
722    Assembler& asmr = handler.assembler;
723   
724    if (asmr.currentKernel==ASMKERN_GLOBAL ||
725        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
726        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
727   
728    if (!checkGarbagesAtEnd(asmr, linePtr))
729        return;
730   
731    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
732    config->enableSgprRegisterFlags = uint16_t(ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER|
733                    ROCMFLAG_USE_DISPATCH_PTR|ROCMFLAG_USE_KERNARG_SEGMENT_PTR);
734    config->enableFeatureFlags = uint16_t(AMDHSAFLAG_USE_PTR64|2);
735}
736
737void AsmROCmPseudoOps::setDimensions(AsmROCmHandler& handler, const char* pseudoOpPlace,
738                  const char* linePtr)
739{
740    Assembler& asmr = handler.assembler;
741    if (asmr.currentKernel==ASMKERN_GLOBAL ||
742        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
743        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
744    cxuint dimMask = 0;
745    if (!parseDimensions(asmr, linePtr, dimMask))
746        return;
747    if (!checkGarbagesAtEnd(asmr, linePtr))
748        return;
749    handler.kernelStates[asmr.currentKernel]->config->dimMask = dimMask;
750}
751
752// parse machine version - used also in AsmGalliumFormat
753// four numbers - kind, major, minor, stepping
754bool AsmROCmPseudoOps::parseMachine(Assembler& asmr, const char* linePtr,
755        uint16_t& machineKind, uint16_t& machineMajor, uint16_t& machineMinor,
756        uint16_t& machineStepping)
757{
758    const char* end = asmr.line + asmr.lineSize;
759   
760    skipSpacesToEnd(linePtr, end);
761    uint64_t kindValue = 0;
762    uint64_t majorValue = 0;
763    uint64_t minorValue = 0;
764    uint64_t steppingValue = 0;
765    const char* valuePlace = linePtr;
766    bool good = getAbsoluteValueArg(asmr, kindValue, linePtr, true);
767    // parse kind
768    asmr.printWarningForRange(16, kindValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
769    if (!skipRequiredComma(asmr, linePtr))
770        return false;
771   
772    valuePlace = linePtr;
773    good &= getAbsoluteValueArg(asmr, majorValue, linePtr, true);
774    // parse major
775    asmr.printWarningForRange(16, majorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
776    if (!skipRequiredComma(asmr, linePtr))
777        return false;
778   
779    valuePlace = linePtr;
780    good &= getAbsoluteValueArg(asmr, minorValue, linePtr, true);
781    // parse minor
782    asmr.printWarningForRange(16, minorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
783    if (!skipRequiredComma(asmr, linePtr))
784        return false;
785   
786    valuePlace = linePtr;
787    // parse stepping
788    good &= getAbsoluteValueArg(asmr, steppingValue, linePtr, true);
789    asmr.printWarningForRange(16, steppingValue,
790                      asmr.getSourcePos(valuePlace), WS_UNSIGNED);
791   
792    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
793        return false;
794   
795    machineKind = kindValue;
796    machineMajor = majorValue;
797    machineMinor = minorValue;
798    machineStepping = steppingValue;
799    return true;
800}
801
802// set machine - four numbers - kind, major, minor, stepping
803void AsmROCmPseudoOps::setMachine(AsmROCmHandler& handler, const char* pseudoOpPlace,
804                      const char* linePtr)
805{
806    Assembler& asmr = handler.assembler;
807    if (asmr.currentKernel==ASMKERN_GLOBAL ||
808        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
809        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
810   
811    uint16_t kindValue = 0, majorValue = 0;
812    uint16_t minorValue = 0, steppingValue = 0;
813    if (!parseMachine(asmr, linePtr, kindValue, majorValue, minorValue, steppingValue))
814        return;
815   
816    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
817    config->amdMachineKind = kindValue;
818    config->amdMachineMajor = majorValue;
819    config->amdMachineMinor = minorValue;
820    config->amdMachineStepping = steppingValue;
821}
822
823// parse code version (amd code version) - used also in AsmGalliumFormat
824// two numbers - major and minor
825bool AsmROCmPseudoOps::parseCodeVersion(Assembler& asmr, const char* linePtr,
826                uint16_t& codeMajor, uint16_t& codeMinor)
827{
828    const char* end = asmr.line + asmr.lineSize;
829   
830    skipSpacesToEnd(linePtr, end);
831    uint64_t majorValue = 0;
832    uint64_t minorValue = 0;
833    const char* valuePlace = linePtr;
834    // parse version major
835    bool good = getAbsoluteValueArg(asmr, majorValue, linePtr, true);
836    asmr.printWarningForRange(32, majorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
837    if (!skipRequiredComma(asmr, linePtr))
838        return false;
839   
840    valuePlace = linePtr;
841    // parse version minor
842    good &= getAbsoluteValueArg(asmr, minorValue, linePtr, true);
843    asmr.printWarningForRange(32, minorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
844   
845    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
846        return false;
847   
848    codeMajor = majorValue;
849    codeMinor = minorValue;
850    return true;
851}
852
853// two numbers - major and minor
854void AsmROCmPseudoOps::setCodeVersion(AsmROCmHandler& handler, const char* pseudoOpPlace,
855                  const char* linePtr)
856{
857    Assembler& asmr = handler.assembler;
858    if (asmr.currentKernel==ASMKERN_GLOBAL ||
859        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
860        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
861   
862    uint16_t majorValue = 0, minorValue = 0;
863    if (!parseCodeVersion(asmr, linePtr, majorValue, minorValue))
864        return;
865   
866    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
867    config->amdCodeVersionMajor = majorValue;
868    config->amdCodeVersionMinor = minorValue;
869}
870
871// parse reserved gprs - used also in AsmGalliumFormat
872// parsereserved S/VGRPS - first number is first register, second is last register
873bool AsmROCmPseudoOps::parseReservedXgprs(Assembler& asmr, const char* linePtr,
874                bool inVgpr, uint16_t& gprFirst, uint16_t& gprCount)
875{
876    const char* end = asmr.line + asmr.lineSize;
877    skipSpacesToEnd(linePtr, end);
878    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(asmr.deviceType);
879    cxuint maxGPRsNum = getGPUMaxRegistersNum(arch,
880                       inVgpr ? REGTYPE_VGPR : REGTYPE_SGPR, 0);
881   
882    uint64_t firstReg = BINGEN_NOTSUPPLIED;
883    uint64_t lastReg = BINGEN_NOTSUPPLIED;
884    const char* valuePlace = linePtr;
885    bool haveFirstReg;
886    bool good = getAbsoluteValueArg(asmr, firstReg, linePtr, true);
887    haveFirstReg = good;
888    if (haveFirstReg && firstReg > maxGPRsNum-1)
889    {
890        // first register is out of range
891        char buf[64];
892        snprintf(buf, 64, "First reserved %s register out of range (0-%u)",
893                 inVgpr ? "VGPR" : "SGPR",  maxGPRsNum-1);
894        ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
895    }
896    if (!skipRequiredComma(asmr, linePtr))
897        return false;
898   
899    valuePlace = linePtr;
900    bool haveLastReg = getAbsoluteValueArg(asmr, lastReg, linePtr, true);
901    good &= haveLastReg;
902    if (haveLastReg && lastReg > maxGPRsNum-1)
903    {
904        // if last register out of range
905        char buf[64];
906        snprintf(buf, 64, "Last reserved %s register out of range (0-%u)",
907                 inVgpr ? "VGPR" : "SGPR", maxGPRsNum-1);
908        ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
909    }
910    if (haveFirstReg && haveLastReg && firstReg > lastReg)
911        ASM_NOTGOOD_BY_ERROR(valuePlace, "Wrong register range")
912   
913    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
914        return false;
915   
916    gprFirst = firstReg;
917    gprCount = lastReg-firstReg+1;
918    return true;
919}
920
921/// set reserved S/VGRPS - first number is first register, second is last register
922void AsmROCmPseudoOps::setReservedXgprs(AsmROCmHandler& handler, const char* pseudoOpPlace,
923                      const char* linePtr, bool inVgpr)
924{
925    Assembler& asmr = handler.assembler;
926    if (asmr.currentKernel==ASMKERN_GLOBAL ||
927        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
928        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
929   
930    uint16_t gprFirst = 0, gprCount = 0;
931    if (!parseReservedXgprs(asmr, linePtr, inVgpr, gprFirst, gprCount))
932        return;
933   
934    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
935    if (inVgpr)
936    {
937        config->reservedVgprFirst = gprFirst;
938        config->reservedVgprCount = gprCount;
939    }
940    else
941    {
942        config->reservedSgprFirst = gprFirst;
943        config->reservedSgprCount = gprCount;
944    }
945}
946
947// set UseGridWorkGroupCount - 3 bits for dimensions
948void AsmROCmPseudoOps::setUseGridWorkGroupCount(AsmROCmHandler& handler,
949                   const char* pseudoOpPlace, const char* linePtr)
950{
951    Assembler& asmr = handler.assembler;
952    if (asmr.currentKernel==ASMKERN_GLOBAL ||
953        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
954        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
955    cxuint dimMask = 0;
956    if (!parseDimensions(asmr, linePtr, dimMask))
957        return;
958    if (!checkGarbagesAtEnd(asmr, linePtr))
959        return;
960    uint16_t& flags = handler.kernelStates[asmr.currentKernel]->config->
961                enableSgprRegisterFlags;
962    flags = (flags & ~(7<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT)) |
963            (dimMask<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT);
964}
965
966void AsmROCmPseudoOps::updateKCodeSel(AsmROCmHandler& handler,
967                  const std::vector<cxuint>& oldset)
968{
969    Assembler& asmr = handler.assembler;
970    // old elements - join current regstate with all them
971    size_t regTypesNum;
972    for (auto it = oldset.begin(); it != oldset.end(); ++it)
973    {
974        Flags curAllocRegFlags;
975        const cxuint* curAllocRegs = asmr.isaAssembler->getAllocatedRegisters(regTypesNum,
976                               curAllocRegFlags);
977        cxuint newAllocRegs[MAX_REGTYPES_NUM];
978        AsmROCmHandler::Kernel& kernel = *(handler.kernelStates[*it]);
979        for (size_t i = 0; i < regTypesNum; i++)
980            newAllocRegs[i] = std::max(curAllocRegs[i], kernel.allocRegs[i]);
981        kernel.allocRegFlags |= curAllocRegFlags;
982        std::copy(newAllocRegs, newAllocRegs+regTypesNum, kernel.allocRegs);
983    }
984    asmr.isaAssembler->setAllocatedRegisters();
985}
986
987void AsmROCmPseudoOps::doKCode(AsmROCmHandler& handler, const char* pseudoOpPlace,
988                  const char* linePtr)
989{
990    Assembler& asmr = handler.assembler;
991    const char* end = asmr.line + asmr.lineSize;
992    bool good = true;
993    skipSpacesToEnd(linePtr, end);
994    if (linePtr==end)
995        return;
996    std::unordered_set<cxuint> newSel(handler.kcodeSelection.begin(),
997                          handler.kcodeSelection.end());
998    do {
999        CString kname;
1000        const char* knamePlace = linePtr;
1001        skipSpacesToEnd(linePtr, end);
1002        bool removeKernel = false;
1003        if (linePtr!=end && *linePtr=='-')
1004        {
1005            // '-' - remove this kernel from current kernel selection
1006            removeKernel = true;
1007            linePtr++;
1008        }
1009        else if (linePtr!=end && *linePtr=='+')
1010        {
1011            linePtr++;
1012            skipSpacesToEnd(linePtr, end);
1013            if (linePtr==end)
1014            {
1015                // add all kernels
1016                for (cxuint k = 0; k < handler.kernelStates.size(); k++)
1017                    newSel.insert(k);
1018                break;
1019            }
1020        }
1021       
1022        if (!getNameArg(asmr, kname, linePtr, "kernel"))
1023        { good = false; continue; }
1024        auto kit = asmr.kernelMap.find(kname);
1025        if (kit == asmr.kernelMap.end())
1026        {
1027            asmr.printError(knamePlace, "Kernel not found");
1028            continue;
1029        }
1030        if (!removeKernel)
1031            newSel.insert(kit->second);
1032        else // remove kernel
1033            newSel.erase(kit->second);
1034    } while (skipCommaForMultipleArgs(asmr, linePtr));
1035   
1036    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1037        return;
1038   
1039    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
1040        PSEUDOOP_RETURN_BY_ERROR("KCode outside code")
1041    if (handler.kcodeSelStack.empty())
1042        handler.saveKcodeCurrentAllocRegs();
1043    // push to stack
1044    handler.kcodeSelStack.push(handler.kcodeSelection);
1045    // set current sel
1046    handler.kcodeSelection.assign(newSel.begin(), newSel.end());
1047    std::sort(handler.kcodeSelection.begin(), handler.kcodeSelection.end());
1048   
1049    const std::vector<cxuint>& oldKCodeSel = handler.kcodeSelStack.top();
1050    if (!oldKCodeSel.empty())
1051        asmr.handleRegionsOnKernels(handler.kcodeSelection, oldKCodeSel,
1052                            handler.codeSection);
1053    else if (handler.currentKcodeKernel != ASMKERN_GLOBAL)
1054    {
1055        std::vector<cxuint> tempKCodeSel;
1056        tempKCodeSel.push_back(handler.currentKcodeKernel);
1057        asmr.handleRegionsOnKernels(handler.kcodeSelection, tempKCodeSel,
1058                            handler.codeSection);
1059    }
1060   
1061    updateKCodeSel(handler, handler.kcodeSelStack.top());
1062}
1063
1064void AsmROCmPseudoOps::doKCodeEnd(AsmROCmHandler& handler, const char* pseudoOpPlace,
1065                  const char* linePtr)
1066{
1067    Assembler& asmr = handler.assembler;
1068    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
1069        PSEUDOOP_RETURN_BY_ERROR("KCodeEnd outside code")
1070    if (handler.kcodeSelStack.empty())
1071        PSEUDOOP_RETURN_BY_ERROR("'.kcodeend' without '.kcode'")
1072    if (!checkGarbagesAtEnd(asmr, linePtr))
1073        return;
1074   
1075    updateKCodeSel(handler, handler.kcodeSelection);
1076    std::vector<cxuint> oldKCodeSel = handler.kcodeSelection;
1077    handler.kcodeSelection = handler.kcodeSelStack.top();
1078   
1079    if (!handler.kcodeSelection.empty())
1080        asmr.handleRegionsOnKernels(handler.kcodeSelection, oldKCodeSel,
1081                        handler.codeSection);
1082    else if (handler.currentKcodeKernel != ASMKERN_GLOBAL)
1083    {
1084        // if choosen current kernel
1085        std::vector<cxuint> curKernelSel;
1086        curKernelSel.push_back(handler.currentKcodeKernel);
1087        asmr.handleRegionsOnKernels(curKernelSel, oldKCodeSel, handler.codeSection);
1088    }
1089   
1090    handler.kcodeSelStack.pop();
1091    if (handler.kcodeSelStack.empty())
1092        handler.restoreKcodeCurrentAllocRegs();
1093}
1094
1095}
1096
1097bool AsmROCmHandler::parsePseudoOp(const CString& firstName, const char* stmtPlace,
1098               const char* linePtr)
1099{
1100    const size_t pseudoOp = binaryFind(rocmPseudoOpNamesTbl, rocmPseudoOpNamesTbl +
1101                    sizeof(rocmPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
1102                   CStringLess()) - rocmPseudoOpNamesTbl;
1103   
1104    switch(pseudoOp)
1105    {
1106        case ROCMOP_ARCH_MINOR:
1107            AsmROCmPseudoOps::setArchMinor(*this, linePtr);
1108            break;
1109        case ROCMOP_ARCH_STEPPING:
1110            AsmROCmPseudoOps::setArchStepping(*this, linePtr);
1111            break;
1112        case ROCMOP_CALL_CONVENTION:
1113            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1114                             ROCMCVAL_CALL_CONVENTION);
1115            break;
1116        case ROCMOP_CODEVERSION:
1117            AsmROCmPseudoOps::setCodeVersion(*this, stmtPlace, linePtr);
1118            break;
1119        case ROCMOP_CONFIG:
1120            AsmROCmPseudoOps::doConfig(*this, stmtPlace, linePtr);
1121            break;
1122        case ROCMOP_CONTROL_DIRECTIVE:
1123            AsmROCmPseudoOps::doControlDirective(*this, stmtPlace, linePtr);
1124            break;
1125        case ROCMOP_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1126            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1127                             ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR);
1128            break;
1129        case ROCMOP_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1130            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1131                         ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR);
1132            break;
1133        case ROCMOP_DEBUGMODE:
1134            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1135                             ROCMCVAL_DEBUGMODE);
1136            break;
1137        case ROCMOP_DIMS:
1138            AsmROCmPseudoOps::setDimensions(*this, stmtPlace, linePtr);
1139            break;
1140        case ROCMOP_DX10CLAMP:
1141            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1142                             ROCMCVAL_DX10CLAMP);
1143            break;
1144        case ROCMOP_EXCEPTIONS:
1145            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1146                             ROCMCVAL_EXCEPTIONS);
1147            break;
1148        case ROCMOP_FKERNEL:
1149            AsmROCmPseudoOps::doFKernel(*this, stmtPlace, linePtr);
1150            break;
1151        case ROCMOP_FLOATMODE:
1152            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1153                             ROCMCVAL_FLOATMODE);
1154            break;
1155        case ROCMOP_GDS_SEGMENT_SIZE:
1156            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1157                             ROCMCVAL_GDS_SEGMENT_SIZE);
1158            break;
1159        case ROCMOP_GROUP_SEGMENT_ALIGN:
1160            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1161                             ROCMCVAL_GROUP_SEGMENT_ALIGN);
1162            break;
1163        case ROCMOP_DEFAULT_HSA_FEATURES:
1164            AsmROCmPseudoOps::setDefaultHSAFeatures(*this, stmtPlace, linePtr);
1165            break;
1166        case ROCMOP_IEEEMODE:
1167            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1168                             ROCMCVAL_IEEEMODE);
1169            break;
1170        case ROCMOP_KCODE:
1171            AsmROCmPseudoOps::doKCode(*this, stmtPlace, linePtr);
1172            break;
1173        case ROCMOP_KCODEEND:
1174            AsmROCmPseudoOps::doKCodeEnd(*this, stmtPlace, linePtr);
1175            break;
1176        case ROCMOP_KERNARG_SEGMENT_ALIGN:
1177            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1178                             ROCMCVAL_KERNARG_SEGMENT_ALIGN);
1179            break;
1180        case ROCMOP_KERNARG_SEGMENT_SIZE:
1181            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1182                             ROCMCVAL_KERNARG_SEGMENT_SIZE);
1183            break;
1184        case ROCMOP_KERNEL_CODE_ENTRY_OFFSET:
1185            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1186                             ROCMCVAL_KERNEL_CODE_ENTRY_OFFSET);
1187            break;
1188        case ROCMOP_KERNEL_CODE_PREFETCH_OFFSET:
1189            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1190                             ROCMCVAL_KERNEL_CODE_PREFETCH_OFFSET);
1191            break;
1192        case ROCMOP_KERNEL_CODE_PREFETCH_SIZE:
1193            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1194                             ROCMCVAL_KERNEL_CODE_PREFETCH_SIZE);
1195            break;
1196        case ROCMOP_LOCALSIZE:
1197            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1198                             ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE);
1199            break;
1200        case ROCMOP_MACHINE:
1201            AsmROCmPseudoOps::setMachine(*this, stmtPlace, linePtr);
1202            break;
1203        case ROCMOP_MAX_SCRATCH_BACKING_MEMORY:
1204            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1205                             ROCMCVAL_MAX_SCRATCH_BACKING_MEMORY);
1206            break;
1207        case ROCMOP_PGMRSRC1:
1208            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PGMRSRC1);
1209            break;
1210        case ROCMOP_PGMRSRC2:
1211            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PGMRSRC2);
1212            break;
1213        case ROCMOP_PRIORITY:
1214            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PRIORITY);
1215            break;
1216        case ROCMOP_PRIVATE_ELEM_SIZE:
1217            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1218                             ROCMCVAL_PRIVATE_ELEM_SIZE);
1219            break;
1220        case ROCMOP_PRIVATE_SEGMENT_ALIGN:
1221            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1222                             ROCMCVAL_PRIVATE_SEGMENT_ALIGN);
1223            break;
1224        case ROCMOP_PRIVMODE:
1225            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1226                             ROCMCVAL_PRIVMODE);
1227            break;
1228        case ROCMOP_RESERVED_SGPRS:
1229            AsmROCmPseudoOps::setReservedXgprs(*this, stmtPlace, linePtr, false);
1230            break;
1231        case ROCMOP_RESERVED_VGPRS:
1232            AsmROCmPseudoOps::setReservedXgprs(*this, stmtPlace, linePtr, true);
1233            break;
1234        case ROCMOP_RUNTIME_LOADER_KERNEL_SYMBOL:
1235            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1236                             ROCMCVAL_RUNTIME_LOADER_KERNEL_SYMBOL);
1237            break;
1238        case ROCMOP_SCRATCHBUFFER:
1239            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1240                             ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE);
1241            break;
1242        case ROCMOP_SGPRSNUM:
1243            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1244                             ROCMCVAL_SGPRSNUM);
1245            break;
1246        case ROCMOP_TGSIZE:
1247            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1248                             ROCMCVAL_TGSIZE);
1249            break;
1250        case ROCMOP_USE_DEBUG_ENABLED:
1251            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1252                             ROCMCVAL_USE_DEBUG_ENABLED);
1253            break;
1254        case ROCMOP_USE_DISPATCH_ID:
1255            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1256                             ROCMCVAL_USE_DISPATCH_ID);
1257            break;
1258        case ROCMOP_USE_DISPATCH_PTR:
1259            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1260                             ROCMCVAL_USE_DISPATCH_PTR);
1261            break;
1262        case ROCMOP_USE_DYNAMIC_CALL_STACK:
1263            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1264                             ROCMCVAL_USE_DYNAMIC_CALL_STACK);
1265            break;
1266        case ROCMOP_USE_FLAT_SCRATCH_INIT:
1267            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1268                             ROCMCVAL_USE_FLAT_SCRATCH_INIT);
1269            break;
1270        case ROCMOP_USE_GRID_WORKGROUP_COUNT:
1271            AsmROCmPseudoOps::setUseGridWorkGroupCount(*this, stmtPlace, linePtr);
1272            break;
1273        case ROCMOP_USE_KERNARG_SEGMENT_PTR:
1274            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1275                             ROCMCVAL_USE_KERNARG_SEGMENT_PTR);
1276            break;
1277        case ROCMOP_USE_ORDERED_APPEND_GDS:
1278            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1279                             ROCMCVAL_USE_ORDERED_APPEND_GDS);
1280            break;
1281        case ROCMOP_USE_PRIVATE_SEGMENT_SIZE:
1282            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1283                             ROCMCVAL_USE_PRIVATE_SEGMENT_SIZE);
1284            break;
1285        case ROCMOP_USE_PTR64:
1286            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1287                             ROCMCVAL_USE_PTR64);
1288            break;
1289        case ROCMOP_USE_QUEUE_PTR:
1290            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1291                             ROCMCVAL_USE_QUEUE_PTR);
1292            break;
1293        case ROCMOP_USE_PRIVATE_SEGMENT_BUFFER:
1294            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1295                             ROCMCVAL_USE_PRIVATE_SEGMENT_BUFFER);
1296            break;
1297        case ROCMOP_USE_XNACK_ENABLED:
1298            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1299                             ROCMCVAL_USE_XNACK_ENABLED);
1300            break;
1301        case ROCMOP_USERDATANUM:
1302            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1303                             ROCMCVAL_USERDATANUM);
1304            break;
1305        case ROCMOP_VGPRSNUM:
1306            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_VGPRSNUM);
1307            break;
1308        case ROCMOP_WAVEFRONT_SGPR_COUNT:
1309            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1310                             ROCMCVAL_WAVEFRONT_SGPR_COUNT);
1311            break;
1312        case ROCMOP_WAVEFRONT_SIZE:
1313            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1314                             ROCMCVAL_WAVEFRONT_SIZE);
1315            break;
1316        case ROCMOP_WORKITEM_VGPR_COUNT:
1317            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1318                             ROCMCVAL_WORKITEM_VGPR_COUNT);
1319            break;
1320        case ROCMOP_WORKGROUP_FBARRIER_COUNT:
1321            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1322                             ROCMCVAL_WORKGROUP_FBARRIER_COUNT);
1323            break;
1324        case ROCMOP_WORKGROUP_GROUP_SEGMENT_SIZE:
1325            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1326                             ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE);
1327            break;
1328        case ROCMOP_WORKITEM_PRIVATE_SEGMENT_SIZE:
1329            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1330                             ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE);
1331            break;
1332        default:
1333            return false;
1334    }
1335    return true;
1336}
1337
1338bool AsmROCmHandler::prepareBinary()
1339{
1340    bool good = true;
1341    size_t sectionsNum = sections.size();
1342    output.deviceType = assembler.getDeviceType();
1343   
1344    if (assembler.isaAssembler!=nullptr)
1345    {
1346        // make last kernel registers pool updates
1347        if (kcodeSelStack.empty())
1348            saveKcodeCurrentAllocRegs();
1349        else
1350            while (!kcodeSelStack.empty())
1351            {
1352                // pop from kcode stack and apply changes
1353                AsmROCmPseudoOps::updateKCodeSel(*this, kcodeSelection);
1354                kcodeSelection = kcodeSelStack.top();
1355                kcodeSelStack.pop();
1356            }
1357    }
1358   
1359    // set sections as outputs
1360    for (size_t i = 0; i < sectionsNum; i++)
1361    {
1362        const AsmSection& asmSection = assembler.sections[i];
1363        const Section& section = sections[i];
1364        const size_t sectionSize = asmSection.getSize();
1365        const cxbyte* sectionData = (!asmSection.content.empty()) ?
1366                asmSection.content.data() : (const cxbyte*)"";
1367        switch(asmSection.type)
1368        {
1369            case AsmSectionType::CODE:
1370                output.codeSize = sectionSize;
1371                output.code = sectionData;
1372                break;
1373            case AsmSectionType::EXTRA_PROGBITS:
1374            case AsmSectionType::EXTRA_NOTE:
1375            case AsmSectionType::EXTRA_NOBITS:
1376            case AsmSectionType::EXTRA_SECTION:
1377            {
1378                // handle extra (user) section, set section type and its flags
1379                uint32_t elfSectType =
1380                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
1381                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
1382                             SHT_PROGBITS;
1383                uint32_t elfSectFlags = 
1384                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
1385                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
1386                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
1387                output.extraSections.push_back({section.name, sectionSize, sectionData,
1388                    asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1389                    elfSectFlags, ELFSECTID_NULL, 0, 0 });
1390                break;
1391            }
1392            case AsmSectionType::ROCM_CONFIG_CTRL_DIRECTIVE:
1393                if (sectionSize != 128)
1394                    // control directive accepts only 128-byte size
1395                    assembler.printError(AsmSourcePos(),
1396                         (std::string("Section '.control_directive' for kernel '")+
1397                          assembler.kernels[section.kernelId].name+
1398                          "' have wrong size").c_str());
1399                break;
1400            case AsmSectionType::ROCM_COMMENT:
1401                output.commentSize = sectionSize;
1402                output.comment = (const char*)sectionData;
1403                break;
1404            default:
1405                break;
1406        }
1407    }
1408   
1409    GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
1410    // set up number of the allocated SGPRs and VGPRs for kernel
1411    cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1412   
1413    AMDGPUArchValues amdGpuArchValues = getGPUArchValues(assembler.deviceType,
1414                                GPUArchValuesTable::OPENSOURCE);
1415    // replace arch minor and stepping by user defined values (if set)
1416    if (output.archMinor!=UINT32_MAX)
1417        amdGpuArchValues.minor = output.archMinor;
1418    if (output.archStepping!=UINT32_MAX)
1419        amdGpuArchValues.stepping = output.archStepping;
1420   
1421    // prepare kernels configuration
1422    for (size_t i = 0; i < kernelStates.size(); i++)
1423    {
1424        const Kernel& kernel = *kernelStates[i];
1425        if (kernel.config.get() == nullptr)
1426            continue;
1427        const CString& kernelName = assembler.kernels[i].name;
1428        AsmROCmKernelConfig& config = *kernel.config.get();
1429        // setup config
1430        // fill default values
1431        if (config.amdCodeVersionMajor == BINGEN_DEFAULT)
1432            config.amdCodeVersionMajor = 1;
1433        if (config.amdCodeVersionMinor == BINGEN_DEFAULT)
1434            config.amdCodeVersionMinor = 0;
1435        if (config.amdMachineKind == BINGEN16_DEFAULT)
1436            config.amdMachineKind = 1;
1437        if (config.amdMachineMajor == BINGEN16_DEFAULT)
1438            config.amdMachineMajor = amdGpuArchValues.major;
1439        if (config.amdMachineMinor == BINGEN16_DEFAULT)
1440            config.amdMachineMinor = amdGpuArchValues.minor;
1441        if (config.amdMachineStepping == BINGEN16_DEFAULT)
1442            config.amdMachineStepping = amdGpuArchValues.stepping;
1443        if (config.kernelCodeEntryOffset == BINGEN64_DEFAULT)
1444            config.kernelCodeEntryOffset = 256;
1445        if (config.kernelCodePrefetchOffset == BINGEN64_DEFAULT)
1446            config.kernelCodePrefetchOffset = 0;
1447        if (config.kernelCodePrefetchSize == BINGEN64_DEFAULT)
1448            config.kernelCodePrefetchSize = 0;
1449        if (config.maxScrachBackingMemorySize == BINGEN64_DEFAULT) // ??
1450            config.maxScrachBackingMemorySize = 0;
1451       
1452        if (config.workitemPrivateSegmentSize == BINGEN_DEFAULT) // scratch buffer
1453            config.workitemPrivateSegmentSize =  0;
1454        if (config.workgroupGroupSegmentSize == BINGEN_DEFAULT) // local size
1455            config.workgroupGroupSegmentSize = 0;
1456        if (config.gdsSegmentSize == BINGEN_DEFAULT)
1457            config.gdsSegmentSize = 0;
1458        if (config.kernargSegmentSize == BINGEN64_DEFAULT)
1459            config.kernargSegmentSize = 0;
1460        if (config.workgroupFbarrierCount == BINGEN_DEFAULT)
1461            config.workgroupFbarrierCount = 0;
1462        if (config.reservedVgprFirst == BINGEN16_DEFAULT)
1463            config.reservedVgprFirst = 0;
1464        if (config.reservedVgprCount == BINGEN16_DEFAULT)
1465            config.reservedVgprCount = 0;
1466        if (config.reservedSgprFirst == BINGEN16_DEFAULT)
1467            config.reservedSgprFirst = 0;
1468        if (config.reservedSgprCount == BINGEN16_DEFAULT)
1469            config.reservedSgprCount = 0;
1470        if (config.debugWavefrontPrivateSegmentOffsetSgpr == BINGEN16_DEFAULT)
1471            config.debugWavefrontPrivateSegmentOffsetSgpr = 0;
1472        if (config.debugPrivateSegmentBufferSgpr == BINGEN16_DEFAULT)
1473            config.debugPrivateSegmentBufferSgpr = 0;
1474        if (config.kernargSegmentAlignment == BINGEN8_DEFAULT)
1475            config.kernargSegmentAlignment = 4; // 16 bytes
1476        if (config.groupSegmentAlignment == BINGEN8_DEFAULT)
1477            config.groupSegmentAlignment = 4; // 16 bytes
1478        if (config.privateSegmentAlignment == BINGEN8_DEFAULT)
1479            config.privateSegmentAlignment = 4; // 16 bytes
1480        if (config.wavefrontSize == BINGEN8_DEFAULT)
1481            config.wavefrontSize = 6; // 64 threads
1482       
1483        cxuint userSGPRsNum = 0;
1484        if (config.userDataNum == BINGEN8_DEFAULT)
1485        {
1486            // calcuate userSGPRs
1487            const uint16_t sgprFlags = config.enableSgprRegisterFlags;
1488            userSGPRsNum =
1489                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER)!=0 ? 4 : 0) +
1490                ((sgprFlags&ROCMFLAG_USE_DISPATCH_PTR)!=0 ? 2 : 0) +
1491                ((sgprFlags&ROCMFLAG_USE_QUEUE_PTR)!=0 ? 2 : 0) +
1492                ((sgprFlags&ROCMFLAG_USE_KERNARG_SEGMENT_PTR)!=0 ? 2 : 0) +
1493                ((sgprFlags&ROCMFLAG_USE_DISPATCH_ID)!=0 ? 2 : 0) +
1494                ((sgprFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0 ? 2 : 0) +
1495                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE)!=0) +
1496                /* use_grid_workgroup_count */
1497                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_X)!=0) +
1498                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Y)!=0) +
1499                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Z)!=0);
1500           userSGPRsNum = std::min(16U, userSGPRsNum);
1501        }
1502        else // default
1503            userSGPRsNum = config.userDataNum;
1504       
1505        /* include userData sgprs */
1506        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
1507                ((config.computePgmRsrc2>>7)&7);
1508        // extra sgprs for dimensions
1509        cxuint minRegsNum[2];
1510        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
1511                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
1512                   ((config.workitemPrivateSegmentSize!=0) ?
1513                           GPUSETUP_SCRATCH_EN : 0), minRegsNum);
1514       
1515        if (config.usedSGPRsNum!=BINGEN_DEFAULT && maxSGPRsNum < config.usedSGPRsNum)
1516        {
1517            // check only if sgprsnum set explicitly
1518            char numBuf[64];
1519            snprintf(numBuf, 64, "(max %u)", maxSGPRsNum);
1520            assembler.printError(assembler.kernels[i].sourcePos, (std::string(
1521                    "Number of total SGPRs for kernel '")+
1522                    kernelName.c_str()+"' is too high "+numBuf).c_str());
1523            good = false;
1524        }
1525        // set usedSGPRsNum
1526        if (config.usedSGPRsNum==BINGEN_DEFAULT)
1527        {
1528            cxuint flags = kernelStates[i]->allocRegFlags |
1529                // flat_scratch_init
1530                ((config.enableSgprRegisterFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0?
1531                            GCN_FLAT : 0) |
1532                // enable_xnack
1533                ((config.enableFeatureFlags&ROCMFLAG_USE_XNACK_ENABLED)!=0 ?
1534                            GCN_XNACK : 0);
1535            config.usedSGPRsNum = std::min(
1536                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]) +
1537                    getGPUExtraRegsNum(arch, REGTYPE_SGPR, flags|GCN_VCC),
1538                    maxSGPRsNum); // include all extra sgprs
1539        }
1540        // set usedVGPRsNum
1541        if (config.usedVGPRsNum==BINGEN_DEFAULT)
1542            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
1543       
1544        cxuint sgprsNum = std::max(config.usedSGPRsNum, 1U);
1545        cxuint vgprsNum = std::max(config.usedVGPRsNum, 1U);
1546        // computePGMRSRC1
1547        config.computePgmRsrc1 |= calculatePgmRSrc1(arch, vgprsNum, sgprsNum,
1548                        config.priority, config.floatMode, config.privilegedMode,
1549                        config.dx10Clamp, config.debugMode, config.ieeeMode);
1550        // computePGMRSRC2
1551        config.computePgmRsrc2 = (config.computePgmRsrc2 & 0xffffe440U) |
1552                calculatePgmRSrc2(arch, (config.workitemPrivateSegmentSize != 0),
1553                            userSGPRsNum, false, config.dimMask,
1554                            (config.computePgmRsrc2 & 0x1b80U), config.tgSize,
1555                            config.workgroupGroupSegmentSize, config.exceptions);
1556       
1557        if (config.wavefrontSgprCount == BINGEN16_DEFAULT)
1558            config.wavefrontSgprCount = sgprsNum;
1559        if (config.workitemVgprCount == BINGEN16_DEFAULT)
1560            config.workitemVgprCount = vgprsNum;
1561       
1562        if (config.callConvention == BINGEN_DEFAULT)
1563            config.callConvention = 0;
1564        if (config.runtimeLoaderKernelSymbol == BINGEN64_DEFAULT)
1565            config.runtimeLoaderKernelSymbol = 0;
1566       
1567        config.toLE(); // to little-endian
1568        // put control directive section to config
1569        if (kernel.ctrlDirSection!=ASMSECT_NONE &&
1570            assembler.sections[kernel.ctrlDirSection].content.size()==128)
1571            ::memcpy(config.controlDirective, 
1572                 assembler.sections[kernel.ctrlDirSection].content.data(), 128);
1573    }
1574   
1575    // if set adds symbols to binary
1576    std::vector<ROCmSymbolInput> dataSymbols;
1577    if (assembler.getFlags() & ASM_FORCE_ADD_SYMBOLS)
1578        for (const AsmSymbolEntry& symEntry: assembler.globalScope.symbolMap)
1579        {
1580            if (!symEntry.second.hasValue)
1581                continue; // unresolved
1582            if (ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
1583                continue; // local
1584            if (assembler.kernelMap.find(symEntry.first.c_str())!=assembler.kernelMap.end())
1585                continue; // if kernel name
1586           
1587            if (symEntry.second.sectionId==codeSection)
1588            {
1589                // put data objects
1590                dataSymbols.push_back({symEntry.first, size_t(symEntry.second.value),
1591                    size_t(symEntry.second.size), ROCmRegionType::DATA});
1592                continue;
1593            }
1594           
1595            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
1596                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
1597            if (binSectId==ELFSECTID_UNDEF)
1598                continue; // no section
1599           
1600            output.extraSymbols.push_back({ symEntry.first, symEntry.second.value,
1601                    symEntry.second.size, binSectId, false, symEntry.second.info,
1602                    symEntry.second.other });
1603        }
1604   
1605    AsmSection& asmCSection = assembler.sections[codeSection];
1606    const AsmSymbolMap& symbolMap = assembler.getSymbolMap();
1607    for (size_t ki = 0; ki < output.symbols.size(); ki++)
1608    {
1609        ROCmSymbolInput& kinput = output.symbols[ki];
1610        auto it = symbolMap.find(kinput.symbolName);
1611        if (it == symbolMap.end() || !it->second.isDefined())
1612        {
1613            // error, undefined
1614            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1615                        "Symbol for kernel '")+kinput.symbolName.c_str()+
1616                        "' is undefined").c_str());
1617            good = false;
1618            continue;
1619        }
1620        const AsmSymbol& symbol = it->second;
1621        if (!symbol.hasValue)
1622        {
1623            // error, unresolved
1624            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1625                    "Symbol for kernel '") + kinput.symbolName.c_str() +
1626                    "' is not resolved").c_str());
1627            good = false;
1628            continue;
1629        }
1630        if (symbol.sectionId != codeSection)
1631        {
1632            /// error, wrong section
1633            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1634                    "Symbol for kernel '")+kinput.symbolName.c_str()+
1635                    "' is defined for section other than '.text'").c_str());
1636            good = false;
1637            continue;
1638        }
1639        const Kernel& kernel = *kernelStates[ki];
1640        kinput.offset = symbol.value;
1641       
1642        if (asmCSection.content.size() < symbol.value + sizeof(ROCmKernelConfig))
1643        {
1644            // if kernel configuration out of section size
1645            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1646                "Code for kernel '")+kinput.symbolName.c_str()+
1647                "' is too small for configuration").c_str());
1648            good = false;
1649            continue;
1650        }
1651        else if (kernel.config!=nullptr)
1652            // put config to code section
1653            ::memcpy(asmCSection.content.data() + symbol.value,
1654                     kernel.config.get(), sizeof(ROCmKernelConfig));
1655        // set symbol type
1656        kinput.type = kernel.isFKernel ? ROCmRegionType::FKERNEL : ROCmRegionType::KERNEL;
1657    }
1658   
1659    // put data objects
1660    dataSymbols.insert(dataSymbols.end(), output.symbols.begin(), output.symbols.end());
1661    output.symbols = std::move(dataSymbols);
1662    return good;
1663}
1664
1665void AsmROCmHandler::writeBinary(std::ostream& os) const
1666{
1667    ROCmBinGenerator binGenerator(&output);
1668    binGenerator.generate(os);
1669}
1670
1671void AsmROCmHandler::writeBinary(Array<cxbyte>& array) const
1672{
1673    ROCmBinGenerator binGenerator(&output);
1674    binGenerator.generate(array);
1675}
Note: See TracBrowser for help on using the repository browser.