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

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

CLRadeonExtender: DisasmROCm: print globalData (rodata) and newbinfmt (if new binary format).
ROCmBinGen: rewrite the creation of mainBuiltinSectionTable: create dynamically. Set eflags by default (if not given). Add globalData (if supplied) to binary.

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