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

Last change on this file since 3671 was 3671, checked in by matszpk, 2 years ago

CLRadeonExtender: AsmROCm: Add '.tripple' to set same LLVM target tripple without device name.
CLRXDocs: add '.tripple' and '.target' descriptions.

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