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

Last change on this file since 3426 was 3426, checked in by matszpk, 18 months ago

CLRadeonExtender: Commenting AsmROCmFormat and AsmGalliumFormat?.

File size: 67.8 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
1338// AMD GPU architecture for Gallium
1339static const AMDGPUArchValues rocmAmdGpuArchValuesTbl[] =
1340{
1341    { 0, 0, 0 }, // GPUDeviceType::CAPE_VERDE
1342    { 0, 0, 0 }, // GPUDeviceType::PITCAIRN
1343    { 0, 0, 0 }, // GPUDeviceType::TAHITI
1344    { 0, 0, 0 }, // GPUDeviceType::OLAND
1345    { 7, 0, 0 }, // GPUDeviceType::BONAIRE
1346    { 7, 0, 0 }, // GPUDeviceType::SPECTRE
1347    { 7, 0, 0 }, // GPUDeviceType::SPOOKY
1348    { 7, 0, 0 }, // GPUDeviceType::KALINDI
1349    { 0, 0, 0 }, // GPUDeviceType::HAINAN
1350    { 7, 0, 1 }, // GPUDeviceType::HAWAII
1351    { 8, 0, 0 }, // GPUDeviceType::ICELAND
1352    { 8, 0, 0 }, // GPUDeviceType::TONGA
1353    { 7, 0, 0 }, // GPUDeviceType::MULLINS
1354    { 8, 0, 3 }, // GPUDeviceType::FIJI
1355    { 8, 0, 1 }, // GPUDeviceType::CARRIZO
1356    { 0, 0, 0 }, // GPUDeviceType::DUMMY
1357    { 0, 0, 0 }, // GPUDeviceType::GOOSE
1358    { 0, 0, 0 }, // GPUDeviceType::HORSE
1359    { 8, 0, 1 }, // GPUDeviceType::STONEY
1360    { 8, 0, 4 }, // GPUDeviceType::ELLESMERE
1361    { 8, 0, 4 }, // GPUDeviceType::BAFFIN
1362    { 8, 0, 4 }, // GPUDeviceType::GFX804
1363    { 9, 0, 0 }, // GPUDeviceType::GFX900
1364    { 9, 0, 1 }  // GPUDeviceType::GFX901
1365};
1366
1367bool AsmROCmHandler::prepareBinary()
1368{
1369    bool good = true;
1370    size_t sectionsNum = sections.size();
1371    output.deviceType = assembler.getDeviceType();
1372   
1373    if (assembler.isaAssembler!=nullptr)
1374    {
1375        // make last kernel registers pool updates
1376        if (kcodeSelStack.empty())
1377            saveKcodeCurrentAllocRegs();
1378        else
1379            while (!kcodeSelStack.empty())
1380            {
1381                // pop from kcode stack and apply changes
1382                AsmROCmPseudoOps::updateKCodeSel(*this, kcodeSelection);
1383                kcodeSelection = kcodeSelStack.top();
1384                kcodeSelStack.pop();
1385            }
1386    }
1387   
1388    // set sections as outputs
1389    for (size_t i = 0; i < sectionsNum; i++)
1390    {
1391        const AsmSection& asmSection = assembler.sections[i];
1392        const Section& section = sections[i];
1393        const size_t sectionSize = asmSection.getSize();
1394        const cxbyte* sectionData = (!asmSection.content.empty()) ?
1395                asmSection.content.data() : (const cxbyte*)"";
1396        switch(asmSection.type)
1397        {
1398            case AsmSectionType::CODE:
1399                output.codeSize = sectionSize;
1400                output.code = sectionData;
1401                break;
1402            case AsmSectionType::EXTRA_PROGBITS:
1403            case AsmSectionType::EXTRA_NOTE:
1404            case AsmSectionType::EXTRA_NOBITS:
1405            case AsmSectionType::EXTRA_SECTION:
1406            {
1407                // handle extra (user) section, set section type and its flags
1408                uint32_t elfSectType =
1409                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
1410                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
1411                             SHT_PROGBITS;
1412                uint32_t elfSectFlags = 
1413                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
1414                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
1415                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
1416                output.extraSections.push_back({section.name, sectionSize, sectionData,
1417                    asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1418                    elfSectFlags, ELFSECTID_NULL, 0, 0 });
1419                break;
1420            }
1421            case AsmSectionType::ROCM_CONFIG_CTRL_DIRECTIVE:
1422                if (sectionSize != 128)
1423                    // control directive accepts only 128-byte size
1424                    assembler.printError(AsmSourcePos(),
1425                         (std::string("Section '.control_directive' for kernel '")+
1426                          assembler.kernels[section.kernelId].name+
1427                          "' have wrong size").c_str());
1428                break;
1429            case AsmSectionType::ROCM_COMMENT:
1430                output.commentSize = sectionSize;
1431                output.comment = (const char*)sectionData;
1432                break;
1433            default:
1434                break;
1435        }
1436    }
1437   
1438    GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
1439    // set up number of the allocated SGPRs and VGPRs for kernel
1440    cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1441   
1442    AMDGPUArchValues amdGpuArchValues = rocmAmdGpuArchValuesTbl[
1443                    cxuint(assembler.deviceType)];
1444    // replace arch minor and stepping by user defined values (if set)
1445    if (output.archMinor!=UINT32_MAX)
1446        amdGpuArchValues.minor = output.archMinor;
1447    if (output.archStepping!=UINT32_MAX)
1448        amdGpuArchValues.stepping = output.archStepping;
1449   
1450    // prepare kernels configuration
1451    for (size_t i = 0; i < kernelStates.size(); i++)
1452    {
1453        const Kernel& kernel = *kernelStates[i];
1454        if (kernel.config.get() == nullptr)
1455            continue;
1456        const CString& kernelName = assembler.kernels[i].name;
1457        AsmROCmKernelConfig& config = *kernel.config.get();
1458        // setup config
1459        // fill default values
1460        if (config.amdCodeVersionMajor == BINGEN_DEFAULT)
1461            config.amdCodeVersionMajor = 1;
1462        if (config.amdCodeVersionMinor == BINGEN_DEFAULT)
1463            config.amdCodeVersionMinor = 0;
1464        if (config.amdMachineKind == BINGEN16_DEFAULT)
1465            config.amdMachineKind = 1;
1466        if (config.amdMachineMajor == BINGEN16_DEFAULT)
1467            config.amdMachineMajor = amdGpuArchValues.major;
1468        if (config.amdMachineMinor == BINGEN16_DEFAULT)
1469            config.amdMachineMinor = amdGpuArchValues.minor;
1470        if (config.amdMachineStepping == BINGEN16_DEFAULT)
1471            config.amdMachineStepping = amdGpuArchValues.stepping;
1472        if (config.kernelCodeEntryOffset == BINGEN64_DEFAULT)
1473            config.kernelCodeEntryOffset = 256;
1474        if (config.kernelCodePrefetchOffset == BINGEN64_DEFAULT)
1475            config.kernelCodePrefetchOffset = 0;
1476        if (config.kernelCodePrefetchSize == BINGEN64_DEFAULT)
1477            config.kernelCodePrefetchSize = 0;
1478        if (config.maxScrachBackingMemorySize == BINGEN64_DEFAULT) // ??
1479            config.maxScrachBackingMemorySize = 0;
1480       
1481        if (config.workitemPrivateSegmentSize == BINGEN_DEFAULT) // scratch buffer
1482            config.workitemPrivateSegmentSize =  0;
1483        if (config.workgroupGroupSegmentSize == BINGEN_DEFAULT) // local size
1484            config.workgroupGroupSegmentSize = 0;
1485        if (config.gdsSegmentSize == BINGEN_DEFAULT)
1486            config.gdsSegmentSize = 0;
1487        if (config.kernargSegmentSize == BINGEN64_DEFAULT)
1488            config.kernargSegmentSize = 0;
1489        if (config.workgroupFbarrierCount == BINGEN_DEFAULT)
1490            config.workgroupFbarrierCount = 0;
1491        if (config.reservedVgprFirst == BINGEN16_DEFAULT)
1492            config.reservedVgprFirst = 0;
1493        if (config.reservedVgprCount == BINGEN16_DEFAULT)
1494            config.reservedVgprCount = 0;
1495        if (config.reservedSgprFirst == BINGEN16_DEFAULT)
1496            config.reservedSgprFirst = 0;
1497        if (config.reservedSgprCount == BINGEN16_DEFAULT)
1498            config.reservedSgprCount = 0;
1499        if (config.debugWavefrontPrivateSegmentOffsetSgpr == BINGEN16_DEFAULT)
1500            config.debugWavefrontPrivateSegmentOffsetSgpr = 0;
1501        if (config.debugPrivateSegmentBufferSgpr == BINGEN16_DEFAULT)
1502            config.debugPrivateSegmentBufferSgpr = 0;
1503        if (config.kernargSegmentAlignment == BINGEN8_DEFAULT)
1504            config.kernargSegmentAlignment = 4; // 16 bytes
1505        if (config.groupSegmentAlignment == BINGEN8_DEFAULT)
1506            config.groupSegmentAlignment = 4; // 16 bytes
1507        if (config.privateSegmentAlignment == BINGEN8_DEFAULT)
1508            config.privateSegmentAlignment = 4; // 16 bytes
1509        if (config.wavefrontSize == BINGEN8_DEFAULT)
1510            config.wavefrontSize = 6; // 64 threads
1511       
1512        cxuint userSGPRsNum = 0;
1513        if (config.userDataNum == BINGEN8_DEFAULT)
1514        {
1515            // calcuate userSGPRs
1516            const uint16_t sgprFlags = config.enableSgprRegisterFlags;
1517            userSGPRsNum =
1518                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER)!=0 ? 4 : 0) +
1519                ((sgprFlags&ROCMFLAG_USE_DISPATCH_PTR)!=0 ? 2 : 0) +
1520                ((sgprFlags&ROCMFLAG_USE_QUEUE_PTR)!=0 ? 2 : 0) +
1521                ((sgprFlags&ROCMFLAG_USE_KERNARG_SEGMENT_PTR)!=0 ? 2 : 0) +
1522                ((sgprFlags&ROCMFLAG_USE_DISPATCH_ID)!=0 ? 2 : 0) +
1523                ((sgprFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0 ? 2 : 0) +
1524                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE)!=0) +
1525                /* use_grid_workgroup_count */
1526                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_X)!=0) +
1527                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Y)!=0) +
1528                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Z)!=0);
1529           userSGPRsNum = std::min(16U, userSGPRsNum);
1530        }
1531        else // default
1532            userSGPRsNum = config.userDataNum;
1533       
1534        /* include userData sgprs */
1535        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
1536                ((config.computePgmRsrc2>>7)&7);
1537        // extra sgprs for dimensions
1538        cxuint minRegsNum[2];
1539        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
1540                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
1541                   ((config.workitemPrivateSegmentSize!=0) ?
1542                           GPUSETUP_SCRATCH_EN : 0), minRegsNum);
1543       
1544        if (config.usedSGPRsNum!=BINGEN_DEFAULT && maxSGPRsNum < config.usedSGPRsNum)
1545        {
1546            // check only if sgprsnum set explicitly
1547            char numBuf[64];
1548            snprintf(numBuf, 64, "(max %u)", maxSGPRsNum);
1549            assembler.printError(assembler.kernels[i].sourcePos, (std::string(
1550                    "Number of total SGPRs for kernel '")+
1551                    kernelName.c_str()+"' is too high "+numBuf).c_str());
1552            good = false;
1553        }
1554        // set usedSGPRsNum
1555        if (config.usedSGPRsNum==BINGEN_DEFAULT)
1556        {
1557            cxuint flags = kernelStates[i]->allocRegFlags |
1558                // flat_scratch_init
1559                ((config.enableSgprRegisterFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0?
1560                            GCN_FLAT : 0) |
1561                // enable_xnack
1562                ((config.enableFeatureFlags&ROCMFLAG_USE_XNACK_ENABLED)!=0 ?
1563                            GCN_XNACK : 0);
1564            config.usedSGPRsNum = std::min(
1565                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]) +
1566                    getGPUExtraRegsNum(arch, REGTYPE_SGPR, flags|GCN_VCC),
1567                    maxSGPRsNum); // include all extra sgprs
1568        }
1569        // set usedVGPRsNum
1570        if (config.usedVGPRsNum==BINGEN_DEFAULT)
1571            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
1572       
1573        cxuint sgprsNum = std::max(config.usedSGPRsNum, 1U);
1574        cxuint vgprsNum = std::max(config.usedVGPRsNum, 1U);
1575        // computePGMRSRC1
1576        config.computePgmRsrc1 |= calculatePgmRSrc1(arch, vgprsNum, sgprsNum,
1577                        config.priority, config.floatMode, config.privilegedMode,
1578                        config.dx10Clamp, config.debugMode, config.ieeeMode);
1579        // computePGMRSRC2
1580        config.computePgmRsrc2 = (config.computePgmRsrc2 & 0xffffe440U) |
1581                calculatePgmRSrc2(arch, (config.workitemPrivateSegmentSize != 0),
1582                            userSGPRsNum, false, config.dimMask,
1583                            (config.computePgmRsrc2 & 0x1b80U), config.tgSize,
1584                            config.workgroupGroupSegmentSize, config.exceptions);
1585       
1586        if (config.wavefrontSgprCount == BINGEN16_DEFAULT)
1587            config.wavefrontSgprCount = sgprsNum;
1588        if (config.workitemVgprCount == BINGEN16_DEFAULT)
1589            config.workitemVgprCount = vgprsNum;
1590       
1591        if (config.callConvention == BINGEN_DEFAULT)
1592            config.callConvention = 0;
1593        if (config.runtimeLoaderKernelSymbol == BINGEN64_DEFAULT)
1594            config.runtimeLoaderKernelSymbol = 0;
1595       
1596        config.toLE(); // to little-endian
1597        // put control directive section to config
1598        if (kernel.ctrlDirSection!=ASMSECT_NONE &&
1599            assembler.sections[kernel.ctrlDirSection].content.size()==128)
1600            ::memcpy(config.controlDirective, 
1601                 assembler.sections[kernel.ctrlDirSection].content.data(), 128);
1602    }
1603   
1604    // if set adds symbols to binary
1605    std::vector<ROCmSymbolInput> dataSymbols;
1606    if (assembler.getFlags() & ASM_FORCE_ADD_SYMBOLS)
1607        for (const AsmSymbolEntry& symEntry: assembler.globalScope.symbolMap)
1608        {
1609            if (!symEntry.second.hasValue)
1610                continue; // unresolved
1611            if (ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
1612                continue; // local
1613            if (assembler.kernelMap.find(symEntry.first.c_str())!=assembler.kernelMap.end())
1614                continue; // if kernel name
1615           
1616            if (symEntry.second.sectionId==codeSection)
1617            {
1618                // put data objects
1619                dataSymbols.push_back({symEntry.first, size_t(symEntry.second.value),
1620                    size_t(symEntry.second.size), ROCmRegionType::DATA});
1621                continue;
1622            }
1623           
1624            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
1625                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
1626            if (binSectId==ELFSECTID_UNDEF)
1627                continue; // no section
1628           
1629            output.extraSymbols.push_back({ symEntry.first, symEntry.second.value,
1630                    symEntry.second.size, binSectId, false, symEntry.second.info,
1631                    symEntry.second.other });
1632        }
1633   
1634    AsmSection& asmCSection = assembler.sections[codeSection];
1635    const AsmSymbolMap& symbolMap = assembler.getSymbolMap();
1636    for (size_t ki = 0; ki < output.symbols.size(); ki++)
1637    {
1638        ROCmSymbolInput& kinput = output.symbols[ki];
1639        auto it = symbolMap.find(kinput.symbolName);
1640        if (it == symbolMap.end() || !it->second.isDefined())
1641        {
1642            // error, undefined
1643            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1644                        "Symbol for kernel '")+kinput.symbolName.c_str()+
1645                        "' is undefined").c_str());
1646            good = false;
1647            continue;
1648        }
1649        const AsmSymbol& symbol = it->second;
1650        if (!symbol.hasValue)
1651        {
1652            // error, unresolved
1653            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1654                    "Symbol for kernel '") + kinput.symbolName.c_str() +
1655                    "' is not resolved").c_str());
1656            good = false;
1657            continue;
1658        }
1659        if (symbol.sectionId != codeSection)
1660        {
1661            /// error, wrong section
1662            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1663                    "Symbol for kernel '")+kinput.symbolName.c_str()+
1664                    "' is defined for section other than '.text'").c_str());
1665            good = false;
1666            continue;
1667        }
1668        const Kernel& kernel = *kernelStates[ki];
1669        kinput.offset = symbol.value;
1670       
1671        if (asmCSection.content.size() < symbol.value + sizeof(ROCmKernelConfig))
1672        {
1673            // if kernel configuration out of section size
1674            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1675                "Code for kernel '")+kinput.symbolName.c_str()+
1676                "' is too small for configuration").c_str());
1677            good = false;
1678            continue;
1679        }
1680        else if (kernel.config!=nullptr)
1681            // put config to code section
1682            ::memcpy(asmCSection.content.data() + symbol.value,
1683                     kernel.config.get(), sizeof(ROCmKernelConfig));
1684        // set symbol type
1685        kinput.type = kernel.isFKernel ? ROCmRegionType::FKERNEL : ROCmRegionType::KERNEL;
1686    }
1687   
1688    // put data objects
1689    dataSymbols.insert(dataSymbols.end(), output.symbols.begin(), output.symbols.end());
1690    output.symbols = std::move(dataSymbols);
1691    return good;
1692}
1693
1694void AsmROCmHandler::writeBinary(std::ostream& os) const
1695{
1696    ROCmBinGenerator binGenerator(&output);
1697    binGenerator.generate(os);
1698}
1699
1700void AsmROCmHandler::writeBinary(Array<cxbyte>& array) const
1701{
1702    ROCmBinGenerator binGenerator(&output);
1703    binGenerator.generate(array);
1704}
Note: See TracBrowser for help on using the repository browser.