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

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

CLRadeonExtender: ROCm: Add eflags support (allow to set or get various e_flags value in ELF header).

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