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

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

CLRadeonExtender: AsmROCm: Add a missing '.runtime_handle' pseudo-ops. add new testcases to test ROCm metadata pseudo-ops.

File size: 99.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 "AsmAmdInternals.h"
32#include "AsmROCmInternals.h"
33
34using namespace CLRX;
35
36// all ROCm pseudo-op names (sorted)
37static const char* rocmPseudoOpNamesTbl[] =
38{
39    "arch_minor", "arch_stepping", "arg",
40    "call_convention", "codeversion", "config",
41    "control_directive", "cws", "debug_private_segment_buffer_sgpr",
42    "debug_wavefront_private_segment_offset_sgpr",
43    "debugmode", "default_hsa_features", "dims", "dx10clamp",
44    "eflags", "exceptions", "fixed_work_group_size",
45    "fkernel", "floatmode", "gds_segment_size",
46    "globaldata", "group_segment_align", "ieeemode", "kcode",
47    "kcodeend", "kernarg_segment_align",
48    "kernarg_segment_size", "kernel_code_entry_offset",
49    "kernel_code_prefetch_offset", "kernel_code_prefetch_size",
50    "localsize", "machine",
51    "max_flat_work_group_size", "max_scratch_backing_memory",
52    "md_group_segment_fixed_size", "md_kernarg_segment_align",
53    "md_kernarg_segment_size", "md_language","md_private_segment_fixed_size",
54    "md_sgprsnum", "md_symname", "md_version",
55    "md_vgprsnum", "md_wavefront_size",
56    "metadata", "newbinfmt", "pgmrsrc1", "pgmrsrc2", "printf", "priority",
57    "private_elem_size", "private_segment_align",
58    "privmode", "reqd_work_group_size",
59    "reserved_sgprs", "reserved_vgprs",
60    "runtime_handle", "runtime_loader_kernel_symbol",
61    "scratchbuffer", "sgprsnum",
62    "spilledsgprs", "spilledvgprs", "target", "tgsize", "tripple",
63    "use_debug_enabled", "use_dispatch_id",
64    "use_dispatch_ptr", "use_dynamic_call_stack",
65    "use_flat_scratch_init", "use_grid_workgroup_count",
66    "use_kernarg_segment_ptr", "use_ordered_append_gds",
67    "use_private_segment_buffer", "use_private_segment_size",
68    "use_ptr64", "use_queue_ptr", "use_xnack_enabled",
69    "userdatanum", "vectypehint", "vgprsnum", "wavefront_sgpr_count",
70    "wavefront_size", "work_group_size_hint", "workgroup_fbarrier_count",
71    "workgroup_group_segment_size", "workitem_private_segment_size",
72    "workitem_vgpr_count"
73};
74
75// all enums for ROCm pseudo-ops
76enum
77{
78    ROCMOP_ARCH_MINOR, ROCMOP_ARCH_STEPPING, ROCMOP_ARG,
79    ROCMOP_CALL_CONVENTION, ROCMOP_CODEVERSION, ROCMOP_CONFIG,
80    ROCMOP_CONTROL_DIRECTIVE, ROCMOP_CWS, ROCMOP_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR,
81    ROCMOP_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR,
82    ROCMOP_DEBUGMODE, ROCMOP_DEFAULT_HSA_FEATURES, ROCMOP_DIMS, ROCMOP_DX10CLAMP,
83    ROCMOP_EFLAGS, ROCMOP_EXCEPTIONS, ROCMOP_FIXED_WORK_GROUP_SIZE, ROCMOP_FKERNEL,
84    ROCMOP_FLOATMODE, ROCMOP_GDS_SEGMENT_SIZE, ROCMOP_GLOBALDATA,
85    ROCMOP_GROUP_SEGMENT_ALIGN, ROCMOP_IEEEMODE, ROCMOP_KCODE,
86    ROCMOP_KCODEEND, ROCMOP_KERNARG_SEGMENT_ALIGN,
87    ROCMOP_KERNARG_SEGMENT_SIZE, ROCMOP_KERNEL_CODE_ENTRY_OFFSET,
88    ROCMOP_KERNEL_CODE_PREFETCH_OFFSET, ROCMOP_KERNEL_CODE_PREFETCH_SIZE,
89    ROCMOP_LOCALSIZE, ROCMOP_MACHINE,
90    ROCMOP_MAX_FLAT_WORK_GROUP_SIZE, ROCMOP_MAX_SCRATCH_BACKING_MEMORY,
91    ROCMOP_MD_GROUP_SEGMENT_FIXED_SIZE, ROCMOP_MD_KERNARG_SEGMENT_ALIGN,
92    ROCMOP_MD_KERNARG_SEGMENT_SIZE, ROCMOP_MD_LANGUAGE,
93    ROCMOP_MD_PRIVATE_SEGMENT_FIXED_SIZE, ROCMOP_MD_SGPRSNUM,
94    ROCMOP_MD_SYMNAME, ROCMOP_MD_VERSION, ROCMOP_MD_VGPRSNUM, ROCMOP_MD_WAVEFRONT_SIZE,
95    ROCMOP_METADATA, ROCMOP_NEWBINFMT, ROCMOP_PGMRSRC1, ROCMOP_PGMRSRC2, ROCMOP_PRINTF,
96    ROCMOP_PRIORITY, ROCMOP_PRIVATE_ELEM_SIZE, ROCMOP_PRIVATE_SEGMENT_ALIGN,
97    ROCMOP_PRIVMODE, ROCMOP_REQD_WORK_GROUP_SIZE,
98    ROCMOP_RESERVED_SGPRS, ROCMOP_RESERVED_VGPRS,
99    ROCMOP_RUNTIME_HANDLE, ROCMOP_RUNTIME_LOADER_KERNEL_SYMBOL,
100    ROCMOP_SCRATCHBUFFER, ROCMOP_SGPRSNUM, ROCMOP_SPILLEDSGPRS, ROCMOP_SPILLEDVGPRS,
101    ROCMOP_TARGET, ROCMOP_TGSIZE, ROCMOP_TRIPPLE,
102    ROCMOP_USE_DEBUG_ENABLED, ROCMOP_USE_DISPATCH_ID,
103    ROCMOP_USE_DISPATCH_PTR, ROCMOP_USE_DYNAMIC_CALL_STACK,
104    ROCMOP_USE_FLAT_SCRATCH_INIT, ROCMOP_USE_GRID_WORKGROUP_COUNT,
105    ROCMOP_USE_KERNARG_SEGMENT_PTR, ROCMOP_USE_ORDERED_APPEND_GDS,
106    ROCMOP_USE_PRIVATE_SEGMENT_BUFFER, ROCMOP_USE_PRIVATE_SEGMENT_SIZE,
107    ROCMOP_USE_PTR64, ROCMOP_USE_QUEUE_PTR, ROCMOP_USE_XNACK_ENABLED,
108    ROCMOP_USERDATANUM, ROCMOP_VECTYPEHINT, ROCMOP_VGPRSNUM, ROCMOP_WAVEFRONT_SGPR_COUNT,
109    ROCMOP_WAVEFRONT_SIZE, ROCM_WORK_GROUP_SIZE_HINT, ROCMOP_WORKGROUP_FBARRIER_COUNT,
110    ROCMOP_WORKGROUP_GROUP_SEGMENT_SIZE, ROCMOP_WORKITEM_PRIVATE_SEGMENT_SIZE,
111    ROCMOP_WORKITEM_VGPR_COUNT
112};
113
114/*
115 * ROCm format handler
116 */
117
118AsmROCmHandler::AsmROCmHandler(Assembler& assembler): AsmFormatHandler(assembler),
119             output{}, codeSection(0), commentSection(ASMSECT_NONE),
120             metadataSection(ASMSECT_NONE), dataSection(ASMSECT_NONE), extraSectionCount(0)
121{
122    output.metadataInfo.initialize();
123    output.archMinor = output.archStepping = UINT32_MAX;
124    output.eflags = BINGEN_DEFAULT;
125    assembler.currentKernel = ASMKERN_GLOBAL;
126    assembler.currentSection = 0;
127    // add text section as first
128    sections.push_back({ ASMKERN_GLOBAL, AsmSectionType::CODE,
129                ELFSECTID_TEXT, ".text" });
130    currentKcodeKernel = ASMKERN_GLOBAL;
131    savedSection = 0;
132}
133
134AsmROCmHandler::~AsmROCmHandler()
135{
136    for (Kernel* kernel: kernelStates)
137        delete kernel;
138}
139
140cxuint AsmROCmHandler::addKernel(const char* kernelName)
141{
142    cxuint thisKernel = output.symbols.size();
143    cxuint thisSection = sections.size();
144    output.addEmptyKernel(kernelName);
145    /// add kernel config section
146    sections.push_back({ thisKernel, AsmSectionType::CONFIG, ELFSECTID_UNDEF, nullptr });
147    kernelStates.push_back(
148        new Kernel{ thisSection, nullptr, false, ASMSECT_NONE, thisSection });
149    output.metadataInfo.kernels.push_back(ROCmKernelMetadata());
150    output.metadataInfo.kernels.back().initialize();
151    output.metadataInfo.kernels.back().name = kernelName;
152   
153    if (assembler.currentKernel == ASMKERN_GLOBAL)
154        savedSection = assembler.currentSection;
155   
156    assembler.currentKernel = thisKernel;
157    assembler.currentSection = thisSection;
158    return thisKernel;
159}
160
161cxuint AsmROCmHandler::addSection(const char* sectionName, cxuint kernelId)
162{
163    const cxuint thisSection = sections.size();
164    Section section;
165    section.kernelId = ASMKERN_GLOBAL;  // we ignore input kernelId, we go to main
166   
167    if (::strcmp(sectionName, ".rodata") == 0)
168    {
169         // data (global data/ rodata) section
170        if (dataSection!=ASMSECT_NONE)
171            throw AsmFormatException("Only section '.rodata' can be in binary");
172        dataSection = thisSection;
173        section.type = AsmSectionType::DATA;
174        section.elfBinSectId = ELFSECTID_RODATA;
175        section.name = ".rodata"; // set static name (available by whole lifecycle)
176    }
177    else if (::strcmp(sectionName, ".text") == 0)
178    {
179         // code section
180        if (codeSection!=ASMSECT_NONE)
181            throw AsmFormatException("Only one section '.text' can be in binary");
182        codeSection = thisSection;
183        section.type = AsmSectionType::CODE;
184        section.elfBinSectId = ELFSECTID_TEXT;
185        section.name = ".text"; // set static name (available by whole lifecycle)
186    }
187    else if (::strcmp(sectionName, ".comment") == 0)
188    {
189         // comment section
190        if (commentSection!=ASMSECT_NONE)
191            throw AsmFormatException("Only one section '.comment' can be in binary");
192        commentSection = thisSection;
193        section.type = AsmSectionType::ROCM_COMMENT;
194        section.elfBinSectId = ELFSECTID_COMMENT;
195        section.name = ".comment"; // set static name (available by whole lifecycle)
196    }
197    else
198    {
199        // extra (user) section
200        auto out = extraSectionMap.insert(std::make_pair(CString(sectionName),
201                    thisSection));
202        if (!out.second)
203            throw AsmFormatException("Section already exists");
204        section.type = AsmSectionType::EXTRA_SECTION;
205        section.elfBinSectId = extraSectionCount++;
206        /// reference entry is available and unchangeable by whole lifecycle of section map
207        section.name = out.first->first.c_str();
208    }
209    sections.push_back(section);
210   
211    assembler.currentKernel = ASMKERN_GLOBAL;
212    assembler.currentSection = thisSection;
213    return thisSection;
214}
215
216cxuint AsmROCmHandler::getSectionId(const char* sectionName) const
217{
218    if (::strcmp(sectionName, ".rodata") == 0) // data
219        return dataSection;
220    else if (::strcmp(sectionName, ".text") == 0) // code
221        return codeSection;
222    else if (::strcmp(sectionName, ".comment") == 0) // comment
223        return commentSection;
224    else
225    {
226        // if extra section, then find it
227        SectionMap::const_iterator it = extraSectionMap.find(sectionName);
228        if (it != extraSectionMap.end())
229            return it->second;
230    }
231    return ASMSECT_NONE;
232}
233
234void AsmROCmHandler::setCurrentKernel(cxuint kernel)
235{
236    if (kernel != ASMKERN_GLOBAL && kernel >= kernelStates.size())
237        throw AsmFormatException("KernelId out of range");
238   
239    if (assembler.currentKernel == ASMKERN_GLOBAL)
240        savedSection = assembler.currentSection;
241    else // if kernel
242        kernelStates[assembler.currentKernel]->savedSection = assembler.currentSection;
243   
244    assembler.currentKernel = kernel;
245    if (kernel != ASMKERN_GLOBAL)
246        assembler.currentSection = kernelStates[kernel]->savedSection;
247    else // default main section
248        assembler.currentSection = savedSection;
249}
250
251void AsmROCmHandler::setCurrentSection(cxuint sectionId)
252{
253    if (sectionId >= sections.size())
254        throw AsmFormatException("SectionId out of range");
255   
256    if (assembler.currentKernel == ASMKERN_GLOBAL)
257        savedSection = assembler.currentSection;
258    else // if kernel
259        kernelStates[assembler.currentKernel]->savedSection = assembler.currentSection;
260   
261    assembler.currentSection = sectionId;
262    assembler.currentKernel = sections[sectionId].kernelId;
263}
264
265
266AsmFormatHandler::SectionInfo AsmROCmHandler::getSectionInfo(cxuint sectionId) const
267{
268    if (sectionId >= sections.size())
269        throw AsmFormatException("Section doesn't exists");
270   
271    AsmFormatHandler::SectionInfo info;
272    info.type = sections[sectionId].type;
273    info.flags = 0;
274    // code is addressable and writeable
275    if (info.type == AsmSectionType::CODE)
276        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE;
277    // any other section (except config) are absolute addressable and writeable
278    else if (info.type != AsmSectionType::CONFIG)
279        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE | ASMSECT_ABS_ADDRESSABLE;
280   
281    info.name = sections[sectionId].name;
282    return info;
283}
284
285void AsmROCmHandler::restoreKcodeCurrentAllocRegs()
286{
287    if (currentKcodeKernel != ASMKERN_GLOBAL)
288    {
289        Kernel& newKernel = *kernelStates[currentKcodeKernel];
290        assembler.isaAssembler->setAllocatedRegisters(newKernel.allocRegs,
291                            newKernel.allocRegFlags);
292    }
293}
294
295void AsmROCmHandler::saveKcodeCurrentAllocRegs()
296{
297    if (currentKcodeKernel != ASMKERN_GLOBAL)
298    {
299        // save other state
300        size_t regTypesNum;
301        Kernel& oldKernel = *kernelStates[currentKcodeKernel];
302        const cxuint* regs = assembler.isaAssembler->getAllocatedRegisters(
303                            regTypesNum, oldKernel.allocRegFlags);
304        std::copy(regs, regs+regTypesNum, oldKernel.allocRegs);
305    }
306}
307
308
309void AsmROCmHandler::handleLabel(const CString& label)
310{
311    if (assembler.sections[assembler.currentSection].type != AsmSectionType::CODE)
312        return;
313    auto kit = assembler.kernelMap.find(label);
314    if (kit == assembler.kernelMap.end())
315        return;
316    if (!kcodeSelection.empty())
317        return; // do not change if inside kcode
318    // add code start
319    assembler.sections[assembler.currentSection].addCodeFlowEntry({
320                    size_t(assembler.currentOutPos), 0, AsmCodeFlowType::START });
321    // save other state
322    saveKcodeCurrentAllocRegs();
323    if (currentKcodeKernel != ASMKERN_GLOBAL)
324        assembler.kernels[currentKcodeKernel].closeCodeRegion(
325                        assembler.sections[codeSection].content.size());
326    // restore this state
327    currentKcodeKernel = kit->second;
328    restoreKcodeCurrentAllocRegs();
329    if (currentKcodeKernel != ASMKERN_GLOBAL)
330        assembler.kernels[currentKcodeKernel].openCodeRegion(
331                        assembler.sections[codeSection].content.size());
332}
333
334void AsmROCmHandler::Kernel::initializeKernelConfig()
335{
336    if (!config)
337    {
338        config.reset(new AsmROCmKernelConfig{});
339        config->initialize();
340    }
341}
342
343namespace CLRX
344{
345
346bool AsmROCmPseudoOps::checkPseudoOpName(const CString& string)
347{
348    if (string.empty() || string[0] != '.')
349        return false;
350    const size_t pseudoOp = binaryFind(rocmPseudoOpNamesTbl, rocmPseudoOpNamesTbl +
351                sizeof(rocmPseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
352               CStringLess()) - rocmPseudoOpNamesTbl;
353    return pseudoOp < sizeof(rocmPseudoOpNamesTbl)/sizeof(char*);
354}
355
356void AsmROCmPseudoOps::setArchMinor(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(cxuint)<<3, value,
366                 asmr.getSourcePos(valuePlace), WS_UNSIGNED);
367    if (!checkGarbagesAtEnd(asmr, linePtr))
368        return;
369    handler.output.archMinor = value;
370}
371
372void AsmROCmPseudoOps::setArchStepping(AsmROCmHandler& handler, const char* linePtr)
373{
374    Assembler& asmr = handler.assembler;
375    const char* end = asmr.line + asmr.lineSize;
376    skipSpacesToEnd(linePtr, end);
377    uint64_t value;
378    const char* valuePlace = linePtr;
379    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
380        return;
381    asmr.printWarningForRange(sizeof(cxuint)<<3, value,
382                 asmr.getSourcePos(valuePlace), WS_UNSIGNED);
383    if (!checkGarbagesAtEnd(asmr, linePtr))
384        return;
385    handler.output.archStepping = value;
386}
387
388void AsmROCmPseudoOps::setEFlags(AsmROCmHandler& handler, const char* linePtr)
389{
390    Assembler& asmr = handler.assembler;
391    const char* end = asmr.line + asmr.lineSize;
392    skipSpacesToEnd(linePtr, end);
393    uint64_t value;
394    const char* valuePlace = linePtr;
395    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
396        return;
397    asmr.printWarningForRange(sizeof(uint32_t)<<3, value,
398                 asmr.getSourcePos(valuePlace), WS_UNSIGNED);
399    if (!checkGarbagesAtEnd(asmr, linePtr))
400        return;
401    handler.output.eflags = value;
402}
403
404void AsmROCmPseudoOps::setTarget(AsmROCmHandler& handler, const char* linePtr,
405                        bool tripple)
406{
407    Assembler& asmr = handler.assembler;
408    const char* end = asmr.line + asmr.lineSize;
409    skipSpacesToEnd(linePtr, end);
410    std::string out;
411    if (!asmr.parseString(out, linePtr))
412        return;
413    if (!checkGarbagesAtEnd(asmr, linePtr))
414        return;
415    if (tripple)
416        handler.output.targetTripple = out;
417    else
418        handler.output.target = out;
419}
420
421void AsmROCmPseudoOps::doConfig(AsmROCmHandler& handler, const char* pseudoOpPlace,
422                  const char* linePtr)
423{
424    Assembler& asmr = handler.assembler;
425    if (asmr.currentKernel==ASMKERN_GLOBAL)
426        PSEUDOOP_RETURN_BY_ERROR("Kernel config can be defined only inside kernel")
427   
428    if (!checkGarbagesAtEnd(asmr, linePtr))
429        return;
430    AsmROCmHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
431    asmr.goToSection(pseudoOpPlace, kernel.configSection);
432    kernel.initializeKernelConfig();
433}
434
435void AsmROCmPseudoOps::doControlDirective(AsmROCmHandler& handler,
436              const char* pseudoOpPlace, const char* linePtr)
437{
438    Assembler& asmr = handler.assembler;
439    if (asmr.currentKernel==ASMKERN_GLOBAL)
440        PSEUDOOP_RETURN_BY_ERROR("Kernel control directive can be defined "
441                    "only inside kernel")
442    if (!checkGarbagesAtEnd(asmr, linePtr))
443        return;
444   
445    AsmROCmHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
446    if (kernel.ctrlDirSection == ASMSECT_NONE)
447    {
448        // define control directive section (if not exists)
449        cxuint thisSection = handler.sections.size();
450        handler.sections.push_back({ asmr.currentKernel,
451            AsmSectionType::ROCM_CONFIG_CTRL_DIRECTIVE,
452            ELFSECTID_UNDEF, nullptr });
453        kernel.ctrlDirSection = thisSection;
454    }
455    asmr.goToSection(pseudoOpPlace, kernel.ctrlDirSection);
456    handler.kernelStates[asmr.currentKernel]->initializeKernelConfig();
457}
458
459void AsmROCmPseudoOps::doGlobalData(AsmROCmHandler& handler,
460                   const char* pseudoOpPlace, const char* linePtr)
461{
462    Assembler& asmr = handler.assembler;
463    if (!checkGarbagesAtEnd(asmr, linePtr))
464        return;
465    // go to global data (named in ELF as '.rodata')
466    asmr.goToSection(pseudoOpPlace, ".rodata");
467}
468
469void AsmROCmPseudoOps::setNewBinFormat(AsmROCmHandler& handler, const char* linePtr)
470{
471    Assembler& asmr = handler.assembler;
472    if (!checkGarbagesAtEnd(asmr, linePtr))
473        return;
474    handler.output.newBinFormat = true;
475}
476
477void AsmROCmPseudoOps::addMetadata(AsmROCmHandler& handler, const char* pseudoOpPlace,
478                      const char* linePtr)
479{
480    Assembler& asmr = handler.assembler;
481   
482    if (handler.output.useMetadataInfo)
483        PSEUDOOP_RETURN_BY_ERROR("Metadata can't be defined if metadata config "
484                    "is already defined")
485   
486    if (!checkGarbagesAtEnd(asmr, linePtr))
487        return;
488   
489    cxuint& metadataSection = handler.metadataSection;
490    if (metadataSection == ASMSECT_NONE)
491    {
492        /* add this section */
493        cxuint thisSection = handler.sections.size();
494        handler.sections.push_back({ ASMKERN_GLOBAL, AsmSectionType::ROCM_METADATA,
495            ELFSECTID_UNDEF, nullptr });
496        metadataSection = thisSection;
497    }
498    asmr.goToSection(pseudoOpPlace, metadataSection);
499}
500
501void AsmROCmPseudoOps::doFKernel(AsmROCmHandler& handler, const char* pseudoOpPlace,
502                      const char* linePtr)
503{
504    Assembler& asmr = handler.assembler;
505    if (asmr.currentKernel==ASMKERN_GLOBAL)
506        PSEUDOOP_RETURN_BY_ERROR(".fkernel can be only inside kernel")
507    if (!checkGarbagesAtEnd(asmr, linePtr))
508        return;
509    // set fkernel flag for kernel
510    handler.kernelStates[asmr.currentKernel]->isFKernel = true;
511}
512
513void AsmROCmPseudoOps::setMetadataVersion(AsmROCmHandler& handler,
514                const char* pseudoOpPlace, const char* linePtr)
515{
516    Assembler& asmr = handler.assembler;
517    const char* end = asmr.line + asmr.lineSize;
518    if (handler.metadataSection != ASMSECT_NONE)
519        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
520                    "metadata section exists")
521   
522    uint64_t mdVerMajor = 0, mdVerMinor = 0;
523    skipSpacesToEnd(linePtr, end);
524    // parse metadata major version
525    const char* valuePlace = linePtr;
526    bool good = true;
527    if (getAbsoluteValueArg(asmr, mdVerMajor, linePtr, true))
528        asmr.printWarningForRange(sizeof(cxuint)<<3, mdVerMajor,
529                    asmr.getSourcePos(valuePlace), WS_UNSIGNED);
530    else
531        good = false;
532    if (!skipRequiredComma(asmr, linePtr))
533        return;
534   
535    // parse metadata minor version
536    skipSpacesToEnd(linePtr, end);
537    valuePlace = linePtr;
538    if (getAbsoluteValueArg(asmr, mdVerMinor, linePtr, true))
539        asmr.printWarningForRange(sizeof(cxuint)<<3, mdVerMinor,
540                    asmr.getSourcePos(valuePlace), WS_UNSIGNED);
541    else
542        good = false;
543    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
544        return;
545   
546    handler.output.useMetadataInfo = true;
547    handler.output.metadataInfo.version[0] = mdVerMajor;
548    handler.output.metadataInfo.version[1] = mdVerMinor;
549}
550
551void AsmROCmPseudoOps::setCWS(AsmROCmHandler& handler, const char* pseudoOpPlace,
552                      const char* linePtr)
553{
554    Assembler& asmr = handler.assembler;
555    const char* end = asmr.line + asmr.lineSize;
556    if (asmr.currentKernel==ASMKERN_GLOBAL ||
557        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
558        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
559   
560    if (handler.metadataSection != ASMSECT_NONE)
561        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
562                    "metadata section exists")
563   
564    skipSpacesToEnd(linePtr, end);
565    uint64_t out[3] = { 1, 1, 1 };
566    // parse CWS (1-3 values)
567    if (!AsmAmdPseudoOps::parseCWS(asmr, pseudoOpPlace, linePtr, out))
568        return;
569    handler.output.useMetadataInfo = true;
570    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
571    // reqd_work_group_size
572    metadata.reqdWorkGroupSize[0] = out[0];
573    metadata.reqdWorkGroupSize[1] = out[1];
574    metadata.reqdWorkGroupSize[2] = out[2];
575}
576
577void AsmROCmPseudoOps::setWorkGroupSizeHint(AsmROCmHandler& handler,
578                    const char* pseudoOpPlace, const char* linePtr)
579{
580    Assembler& asmr = handler.assembler;
581    const char* end = asmr.line + asmr.lineSize;
582    if (asmr.currentKernel==ASMKERN_GLOBAL ||
583        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
584        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
585   
586    if (handler.metadataSection != ASMSECT_NONE)
587        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
588                    "metadata section exists")
589   
590    skipSpacesToEnd(linePtr, end);
591    uint64_t out[3] = { 1, 1, 1 };
592    // parse CWS (1-3 values)
593    if (!AsmAmdPseudoOps::parseCWS(asmr, pseudoOpPlace, linePtr, out))
594        return;
595    handler.output.useMetadataInfo = true;
596    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
597    // work group size hint
598    metadata.workGroupSizeHint[0] = out[0];
599    metadata.workGroupSizeHint[1] = out[1];
600    metadata.workGroupSizeHint[2] = out[2];
601}
602
603void AsmROCmPseudoOps::setFixedWorkGroupSize(AsmROCmHandler& handler,
604                    const char* pseudoOpPlace, const char* linePtr)
605{
606    Assembler& asmr = handler.assembler;
607    const char* end = asmr.line + asmr.lineSize;
608    if (asmr.currentKernel==ASMKERN_GLOBAL ||
609        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
610        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
611   
612    if (handler.metadataSection != ASMSECT_NONE)
613        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
614                    "metadata section exists")
615   
616    skipSpacesToEnd(linePtr, end);
617    uint64_t out[3] = { 1, 1, 1 };
618    // parse CWS (1-3 values)
619    if (!AsmAmdPseudoOps::parseCWS(asmr, pseudoOpPlace, linePtr, out))
620        return;
621    handler.output.useMetadataInfo = true;
622    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
623    // fixed work group size
624    metadata.fixedWorkGroupSize[0] = out[0];
625    metadata.fixedWorkGroupSize[1] = out[1];
626    metadata.fixedWorkGroupSize[2] = out[2];
627}
628
629void AsmROCmPseudoOps::setVecTypeHint(AsmROCmHandler& handler, const char* pseudoOpPlace,
630                      const char* linePtr)
631{
632    Assembler& asmr = handler.assembler;
633    const char* end = asmr.line + asmr.lineSize;
634    if (asmr.currentKernel==ASMKERN_GLOBAL ||
635        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
636        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
637   
638    if (handler.metadataSection != ASMSECT_NONE)
639        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
640                    "metadata section exists")
641   
642    CString vecTypeHint;
643    skipSpacesToEnd(linePtr, end);
644    bool good = getNameArg(asmr, vecTypeHint, linePtr, "vectypehint", true);
645    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
646        return;
647   
648    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
649    handler.output.useMetadataInfo = true;
650    metadata.vecTypeHint = vecTypeHint;
651}
652
653void AsmROCmPseudoOps::setKernelSymName(AsmROCmHandler& handler, const char* pseudoOpPlace,
654                      const char* linePtr)
655{
656    Assembler& asmr = handler.assembler;
657    const char* end = asmr.line + asmr.lineSize;
658    if (asmr.currentKernel==ASMKERN_GLOBAL ||
659        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
660        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
661   
662    if (handler.metadataSection != ASMSECT_NONE)
663        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
664                    "metadata section exists")
665   
666    std::string symName;
667    skipSpacesToEnd(linePtr, end);
668    bool good = asmr.parseString(symName, linePtr);
669    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
670        return;
671   
672    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
673    handler.output.useMetadataInfo = true;
674    metadata.symbolName = symName;
675}
676
677void AsmROCmPseudoOps::setKernelLanguage(AsmROCmHandler& handler, const char* pseudoOpPlace,
678                      const char* linePtr)
679{
680    Assembler& asmr = handler.assembler;
681    const char* end = asmr.line + asmr.lineSize;
682    if (asmr.currentKernel==ASMKERN_GLOBAL ||
683        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
684        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
685   
686    if (handler.metadataSection != ASMSECT_NONE)
687        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
688                    "metadata section exists")
689   
690    std::string langName;
691    skipSpacesToEnd(linePtr, end);
692    bool good = asmr.parseString(langName, linePtr);
693   
694    uint64_t langVerMajor = 0, langVerMinor = 0;
695    skipSpacesToEnd(linePtr, end);
696    if (linePtr != end)
697    {
698        if (!skipRequiredComma(asmr, linePtr))
699            return;
700       
701        skipSpacesToEnd(linePtr, end);
702        // parse language major version
703        const char* valuePlace = linePtr;
704        if (getAbsoluteValueArg(asmr, langVerMajor, linePtr, true))
705            asmr.printWarningForRange(sizeof(cxuint)<<3, langVerMajor,
706                        asmr.getSourcePos(valuePlace), WS_UNSIGNED);
707        else
708            good = false;
709        if (!skipRequiredComma(asmr, linePtr))
710            return;
711       
712        // parse language major version
713        skipSpacesToEnd(linePtr, end);
714        valuePlace = linePtr;
715        if (getAbsoluteValueArg(asmr, langVerMinor, linePtr, true))
716            asmr.printWarningForRange(sizeof(cxuint)<<3, langVerMinor,
717                        asmr.getSourcePos(valuePlace), WS_UNSIGNED);
718        else
719            good = false;
720    }
721   
722    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
723        return;
724   
725    // just set language
726    handler.output.useMetadataInfo = true;
727    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
728    metadata.language = langName;
729    metadata.langVersion[0] = langVerMajor;
730    metadata.langVersion[1] = langVerMinor;
731}
732
733void AsmROCmPseudoOps::setRuntimeHandle(AsmROCmHandler& handler, const char* pseudoOpPlace,
734                      const char* linePtr)
735{
736    Assembler& asmr = handler.assembler;
737    const char* end = asmr.line + asmr.lineSize;
738    if (asmr.currentKernel==ASMKERN_GLOBAL ||
739        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
740        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
741   
742    if (handler.metadataSection != ASMSECT_NONE)
743        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
744                    "metadata section exists")
745   
746    std::string runtimeHandle;
747    skipSpacesToEnd(linePtr, end);
748    bool good = asmr.parseString(runtimeHandle, linePtr);
749    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
750        return;
751   
752    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
753    handler.output.useMetadataInfo = true;
754    metadata.runtimeHandle = runtimeHandle;
755
756}
757
758void AsmROCmPseudoOps::addPrintf(AsmROCmHandler& handler, const char* pseudoOpPlace,
759                      const char* linePtr)
760{
761    Assembler& asmr = handler.assembler;
762    const char* end = asmr.line + asmr.lineSize;
763    if (handler.metadataSection != ASMSECT_NONE)
764        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
765                    "metadata section exists")
766   
767    ROCmPrintfInfo printfInfo{};
768    uint64_t printfId = BINGEN_DEFAULT;
769    skipSpacesToEnd(linePtr, end);
770    // parse printf id
771    const char* valuePlace = linePtr;
772    bool good = true;
773    if (getAbsoluteValueArg(asmr, printfId, linePtr))
774        asmr.printWarningForRange(sizeof(cxuint)<<3, printfId,
775                            asmr.getSourcePos(valuePlace), WS_UNSIGNED);
776    else
777        good = false;
778    printfInfo.id = printfId;
779   
780    if (!skipRequiredComma(asmr, linePtr))
781        return;
782   
783    std::vector<uint32_t> argSizes;
784    skipSpacesToEnd(linePtr, end);
785    // parse argument sizes
786    while (linePtr != end && *linePtr!='\"')
787    {
788        uint64_t argSize = 0;
789        valuePlace = linePtr;
790        if (getAbsoluteValueArg(asmr, argSize, linePtr, true))
791            asmr.printWarningForRange(sizeof(cxuint)<<3, argSize,
792                            asmr.getSourcePos(valuePlace), WS_UNSIGNED);
793        else
794            good = false;
795        argSizes.push_back(uint32_t(argSize));
796       
797        if (!skipRequiredComma(asmr, linePtr))
798            return;
799        skipSpacesToEnd(linePtr, end);
800    }
801    printfInfo.argSizes.assign(argSizes.begin(), argSizes.end());
802   
803    if (linePtr == end)
804        PSEUDOOP_RETURN_BY_ERROR("Missing format string")
805    // parse format
806    std::string formatStr;
807    good &= asmr.parseString(formatStr, linePtr);
808    printfInfo.format = formatStr;
809   
810    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
811        return;
812    handler.output.useMetadataInfo = true;
813    // just add new printf
814    handler.output.metadataInfo.printfInfos.push_back(printfInfo);
815}
816
817static const std::pair<const char*, cxuint> rocmValueKindNamesTbl[] =
818{
819    { "complact", cxuint(ROCmValueKind::HIDDEN_COMPLETION_ACTION) },
820    { "defqueue", cxuint(ROCmValueKind::HIDDEN_DEFAULT_QUEUE) },
821    { "dynshptr", cxuint(ROCmValueKind::DYN_SHARED_PTR) },
822    { "globalbuf", cxuint(ROCmValueKind::GLOBAL_BUFFER) },
823    { "globaloffsetx", cxuint(ROCmValueKind::HIDDEN_GLOBAL_OFFSET_X) },
824    { "globaloffsety", cxuint(ROCmValueKind::HIDDEN_GLOBAL_OFFSET_X) },
825    { "globaloffsetz", cxuint(ROCmValueKind::HIDDEN_GLOBAL_OFFSET_X) },
826    { "gox", cxuint(ROCmValueKind::HIDDEN_GLOBAL_OFFSET_X) },
827    { "goy", cxuint(ROCmValueKind::HIDDEN_GLOBAL_OFFSET_Y) },
828    { "goz", cxuint(ROCmValueKind::HIDDEN_GLOBAL_OFFSET_Z) },
829    { "image", cxuint(ROCmValueKind::IMAGE) },
830    { "none", cxuint(ROCmValueKind::HIDDEN_NONE) },
831    { "pipe", cxuint(ROCmValueKind::PIPE) },
832    { "printfbuf", cxuint(ROCmValueKind::HIDDEN_PRINTF_BUFFER) },
833    { "queue", cxuint(ROCmValueKind::QUEUE) },
834    { "sampler", cxuint(ROCmValueKind::SAMPLER) },
835    { "value", cxuint(ROCmValueKind::BY_VALUE) }
836};
837
838static const size_t rocmValueKindNamesTblSize =
839        sizeof(rocmValueKindNamesTbl) / sizeof(std::pair<const char*, cxuint>);
840
841static const std::pair<const char*, cxuint> rocmValueTypeNamesTbl[] =
842{
843    { "char", cxuint(ROCmValueType::INT8) },
844    { "double", cxuint(ROCmValueType::FLOAT64) },
845    { "f16", cxuint(ROCmValueType::FLOAT16) },
846    { "f32", cxuint(ROCmValueType::FLOAT32) },
847    { "f64", cxuint(ROCmValueType::FLOAT64) },
848    { "float", cxuint(ROCmValueType::FLOAT32) },
849    { "half", cxuint(ROCmValueType::FLOAT16) },
850    { "i16", cxuint(ROCmValueType::INT16) },
851    { "i32", cxuint(ROCmValueType::INT32) },
852    { "i64", cxuint(ROCmValueType::INT64) },
853    { "i8", cxuint(ROCmValueType::INT8) },
854    { "int", cxuint(ROCmValueType::INT32) },
855    { "long", cxuint(ROCmValueType::INT64) },
856    { "short", cxuint(ROCmValueType::INT16) },
857    { "struct", cxuint(ROCmValueType::STRUCTURE) },
858    { "u16", cxuint(ROCmValueType::UINT16) },
859    { "u32", cxuint(ROCmValueType::UINT32) },
860    { "u64", cxuint(ROCmValueType::UINT64) },
861    { "u8", cxuint(ROCmValueType::UINT8) },
862    { "uchar", cxuint(ROCmValueType::UINT8) },
863    { "uint", cxuint(ROCmValueType::UINT32) },
864    { "ulong", cxuint(ROCmValueType::UINT64) },
865    { "ushort", cxuint(ROCmValueType::INT16) }
866};
867
868static const size_t rocmValueTypeNamesTblSize =
869        sizeof(rocmValueTypeNamesTbl) / sizeof(std::pair<const char*, cxuint>);
870
871static const std::pair<const char*, cxuint> rocmAddressSpaceNamesTbl[] =
872{
873    { "constant", cxuint(ROCmAddressSpace::CONSTANT) },
874    { "generic", cxuint(ROCmAddressSpace::GENERIC) },
875    { "global", cxuint(ROCmAddressSpace::GLOBAL) },
876    { "local", cxuint(ROCmAddressSpace::LOCAL) },
877    { "private", cxuint(ROCmAddressSpace::PRIVATE) },
878    { "region", cxuint(ROCmAddressSpace::REGION) }
879};
880
881static const std::pair<const char*, cxuint> rocmAccessQualNamesTbl[] =
882{
883    { "default", cxuint(ROCmAccessQual::DEFAULT) },
884    { "read_only", cxuint(ROCmAccessQual::READ_ONLY) },
885    { "read_write", cxuint(ROCmAccessQual::READ_WRITE) },
886    { "write_only", cxuint(ROCmAccessQual::WRITE_ONLY) }
887};
888
889// add kernel argument (to metadata)
890void AsmROCmPseudoOps::addKernelArg(AsmROCmHandler& handler, const char* pseudoOpPlace,
891                    const char* linePtr)
892{
893    Assembler& asmr = handler.assembler;
894    const char* end = asmr.line + asmr.lineSize;
895    if (asmr.currentKernel==ASMKERN_GLOBAL ||
896        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
897        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
898   
899    if (handler.metadataSection != ASMSECT_NONE)
900        PSEUDOOP_RETURN_BY_ERROR("Metadata config can't be defined if "
901                    "metadata section exists")
902   
903    bool good = true;
904    skipSpacesToEnd(linePtr, end);
905    CString argName;
906    if (linePtr!=end && *linePtr!=',')
907        // parse name
908        good &= getNameArg(asmr, argName, linePtr, "argument name", true);
909   
910    if (!skipRequiredComma(asmr, linePtr))
911        return;
912    skipSpacesToEnd(linePtr, end);
913   
914    std::string typeName;
915    if (linePtr!=end && *linePtr=='"')
916    {
917        // parse arg type
918        good &= asmr.parseString(typeName, linePtr);
919       
920        if (!skipRequiredComma(asmr, linePtr))
921            return;
922    }
923    // parse argument size
924    uint64_t argSize = 0;
925    const char* sizePlace = linePtr;
926    if (getAbsoluteValueArg(asmr, argSize, linePtr, true))
927    {
928        if (argSize == 0)
929            ASM_NOTGOOD_BY_ERROR(sizePlace, "Argument size is zero")
930    }
931    else
932        good = false;
933    if (!skipRequiredComma(asmr, linePtr))
934        return;
935   
936    skipSpacesToEnd(linePtr, end);
937    // parse argument alignment
938    uint64_t argAlign = 0;
939    if (linePtr!=end && *linePtr!=',')
940    {
941        const char* valuePlace = linePtr;
942        if (getAbsoluteValueArg(asmr, argAlign, linePtr, true))
943        {
944            if (argAlign==0 || argAlign != (1ULL<<(63-CLZ64(argAlign))))
945                ASM_NOTGOOD_BY_ERROR(valuePlace, "Argument alignment is not power of 2")
946        }
947        else
948            good = false;
949    }
950    if (argAlign == 0)
951    {
952        argAlign = (argSize!=0) ? 1ULL<<(63-CLZ64(argSize)) : 1;
953        if (argSize > argAlign)
954            argAlign <<= 1;
955    }
956   
957    if (!skipRequiredComma(asmr, linePtr))
958        return;
959   
960    // get value kind
961    cxuint valueKindVal = 0;
962    good &= getEnumeration(asmr, linePtr, "value kind", rocmValueKindNamesTblSize,
963                rocmValueKindNamesTbl, valueKindVal, nullptr);
964    if (!skipRequiredComma(asmr, linePtr))
965        return;
966   
967    // get value type
968    cxuint valueTypeVal = 0;
969    good &= getEnumeration(asmr, linePtr, "value type", rocmValueTypeNamesTblSize,
970                rocmValueTypeNamesTbl, valueTypeVal, nullptr);
971   
972    uint64_t pointeeAlign = 0;
973    if (valueKindVal == cxuint(ROCmValueKind::DYN_SHARED_PTR))
974    {
975        // parse pointeeAlign
976        if (!skipRequiredComma(asmr, linePtr))
977            return;
978        const char* valuePlace = linePtr;
979        if (getAbsoluteValueArg(asmr, pointeeAlign, linePtr, true))
980        {
981            if (pointeeAlign==0 || pointeeAlign != (1ULL<<(63-CLZ64(pointeeAlign))))
982                ASM_NOTGOOD_BY_ERROR(valuePlace, "Argument pointee alignment "
983                            "is not power of 2")
984        }
985        else
986            good = false;
987    }
988   
989    cxuint addressSpaceVal = 0;
990    if (valueKindVal == cxuint(ROCmValueKind::DYN_SHARED_PTR) ||
991        valueKindVal == cxuint(ROCmValueKind::GLOBAL_BUFFER))
992    {
993        if (!skipRequiredComma(asmr, linePtr))
994            return;
995        // parse address space
996        good &= getEnumeration(asmr, linePtr, "address space",
997                    6, rocmAddressSpaceNamesTbl, addressSpaceVal, nullptr);
998    }
999   
1000    bool haveComma = false;
1001    cxuint accessQualVal = 0;
1002    if (valueKindVal == cxuint(ROCmValueKind::IMAGE) ||
1003        valueKindVal == cxuint(ROCmValueKind::PIPE))
1004    {
1005        if (!skipComma(asmr, haveComma, linePtr, false))
1006            return;
1007        // parse access qualifier
1008        if (haveComma)
1009            good &= getEnumeration(asmr, linePtr, "access qualifier",
1010                        4, rocmAccessQualNamesTbl, accessQualVal, nullptr);
1011    }
1012    cxuint actualAccessQualVal = 0;
1013    if (valueKindVal == cxuint(ROCmValueKind::GLOBAL_BUFFER) ||
1014        valueKindVal == cxuint(ROCmValueKind::IMAGE) ||
1015        valueKindVal == cxuint(ROCmValueKind::PIPE))
1016    {
1017        if (!skipComma(asmr, haveComma, linePtr, false))
1018            return;
1019        // parse actual access qualifier
1020        if (haveComma)
1021            good &= getEnumeration(asmr, linePtr, "access qualifier",
1022                    4, rocmAccessQualNamesTbl, actualAccessQualVal, nullptr);
1023    }
1024   
1025    bool argIsConst = false;
1026    bool argIsRestrict = false;
1027    bool argIsVolatile = false;
1028    bool argIsPipe = false;
1029    // parse list of flags
1030    skipSpacesToEnd(linePtr, end);
1031    while (linePtr != end)
1032    {
1033        char name[20];
1034        const char* fieldPlace = linePtr;
1035        if (!getNameArg(asmr, 20, name, linePtr, "argument flag", true))
1036        {
1037            good = false;
1038            break;
1039        }
1040       
1041        if (::strcmp(name, "const")==0)
1042            argIsConst = true;
1043        else if (::strcmp(name, "restrict")==0)
1044            argIsRestrict= true;
1045        else if (::strcmp(name, "volatile")==0)
1046            argIsVolatile = true;
1047        else if (::strcmp(name, "pipe")==0)
1048            argIsPipe = true;
1049        else
1050        {
1051            ASM_NOTGOOD_BY_ERROR(fieldPlace, "Unknown argument flag")
1052            break;
1053        }
1054    }
1055   
1056    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1057        return;
1058   
1059    handler.output.useMetadataInfo = true;
1060    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
1061    // setup kernel arg info
1062    ROCmKernelArgInfo argInfo{};
1063    argInfo.name = argName;
1064    argInfo.typeName = typeName;
1065    argInfo.size = argSize;
1066    argInfo.align = argAlign;
1067    argInfo.pointeeAlign = pointeeAlign;
1068    argInfo.valueKind = ROCmValueKind(valueKindVal);
1069    argInfo.valueType = ROCmValueType(valueTypeVal);
1070    argInfo.addressSpace = ROCmAddressSpace(addressSpaceVal);
1071    argInfo.accessQual = ROCmAccessQual(accessQualVal);
1072    argInfo.actualAccessQual = ROCmAccessQual(actualAccessQualVal);
1073    argInfo.isConst = argIsConst;
1074    argInfo.isRestrict = argIsRestrict;
1075    argInfo.isVolatile = argIsVolatile;
1076    argInfo.isPipe = argIsPipe;
1077    // just add to kernel arguments
1078    metadata.argInfos.push_back(argInfo);
1079}
1080
1081bool AsmROCmPseudoOps::checkConfigValue(Assembler& asmr, const char* valuePlace,
1082                ROCmConfigValueTarget target, uint64_t value)
1083{
1084    bool good = true;
1085    switch(target)
1086    {
1087        case ROCMCVAL_SGPRSNUM:
1088        {
1089            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1090                        asmr.deviceType);
1091            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1092            if (value > maxSGPRsNum)
1093            {
1094                char buf[64];
1095                snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
1096                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1097            }
1098            break;
1099        }
1100        case ROCMCVAL_VGPRSNUM:
1101        {
1102            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1103                        asmr.deviceType);
1104            cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
1105            if (value > maxVGPRsNum)
1106            {
1107                char buf[64];
1108                snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
1109                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1110            }
1111            break;
1112        }
1113        case ROCMCVAL_EXCEPTIONS:
1114            asmr.printWarningForRange(7, value,
1115                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1116            value &= 0x7f;
1117            break;
1118        case ROCMCVAL_FLOATMODE:
1119            asmr.printWarningForRange(8, value,
1120                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1121            value &= 0xff;
1122            break;
1123        case ROCMCVAL_PRIORITY:
1124            asmr.printWarningForRange(2, value,
1125                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1126            value &= 3;
1127            break;
1128        case ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE: // local size
1129        {
1130            asmr.printWarningForRange(32, value,
1131                        asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1132           
1133            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1134                        asmr.deviceType);
1135            const cxuint maxLocalSize = getGPUMaxLocalSize(arch);
1136            if (value > maxLocalSize)
1137            {
1138                char buf[64];
1139                snprintf(buf, 64, "LocalSize out of range (0-%u)", maxLocalSize);
1140                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1141            }
1142            break;
1143        }
1144        case ROCMCVAL_USERDATANUM:
1145            if (value > 16)
1146                ASM_NOTGOOD_BY_ERROR(valuePlace, "UserDataNum out of range (0-16)")
1147            break;
1148        case ROCMCVAL_PRIVATE_ELEM_SIZE:
1149            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1150                ASM_NOTGOOD_BY_ERROR(valuePlace,
1151                                "Private element size must be power of two")
1152            else if (value < 2 || value > 16)
1153                ASM_NOTGOOD_BY_ERROR(valuePlace, "Private element size out of range")
1154            break;
1155        case ROCMCVAL_KERNARG_SEGMENT_ALIGN:
1156        case ROCMCVAL_GROUP_SEGMENT_ALIGN:
1157        case ROCMCVAL_PRIVATE_SEGMENT_ALIGN:
1158            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1159                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment must be power of two")
1160            else if (value < 16)
1161                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment must be not smaller than 16")
1162            break;
1163        case ROCMCVAL_WAVEFRONT_SIZE:
1164            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1165                ASM_NOTGOOD_BY_ERROR(valuePlace, "Wavefront size must be power of two")
1166            else if (value > 256)
1167                ASM_NOTGOOD_BY_ERROR(valuePlace,
1168                            "Wavefront size must be not greater than 256")
1169            break;
1170        case ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE:
1171        case ROCMCVAL_GDS_SEGMENT_SIZE:
1172        case ROCMCVAL_WORKGROUP_FBARRIER_COUNT:
1173        case ROCMCVAL_CALL_CONVENTION:
1174        case ROCMCVAL_PGMRSRC1:
1175        case ROCMCVAL_PGMRSRC2:
1176            asmr.printWarningForRange(32, value,
1177                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1178            break;
1179        case ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1180        case ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1181        {
1182            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1183                        asmr.deviceType);
1184            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1185            if (value >= maxSGPRsNum)
1186                ASM_NOTGOOD_BY_ERROR(valuePlace, "SGPR register out of range")
1187            break;
1188        }
1189        default:
1190            break;
1191    }
1192    return good;
1193}
1194
1195// check metadata config values
1196bool AsmROCmPseudoOps::checkMDConfigValue(Assembler& asmr, const char* valuePlace,
1197                ROCmConfigValueTarget target, uint64_t value)
1198{
1199    bool good = true;
1200    switch(target)
1201    {
1202        case ROCMCVAL_MD_WAVEFRONT_SIZE:
1203            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1204                ASM_NOTGOOD_BY_ERROR(valuePlace, "Wavefront size must be power of two")
1205            else if (value > 256)
1206                ASM_NOTGOOD_BY_ERROR(valuePlace,
1207                            "Wavefront size must be not greater than 256")
1208            break;
1209        case ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN:
1210            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1211                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment size must be power of two")
1212            break;
1213        case ROCMCVAL_MD_SGPRSNUM:
1214        {
1215            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1216                        asmr.deviceType);
1217            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1218            if (value > maxSGPRsNum)
1219            {
1220                char buf[64];
1221                snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
1222                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1223            }
1224            break;
1225        }
1226        case ROCMCVAL_MD_VGPRSNUM:
1227        {
1228            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1229                        asmr.deviceType);
1230            cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
1231            if (value > maxVGPRsNum)
1232            {
1233                char buf[64];
1234                snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
1235                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1236            }
1237            break;
1238        }
1239        default:
1240            break;
1241    }
1242    return good;
1243}
1244
1245void AsmROCmPseudoOps::setConfigValueMain(AsmAmdHsaKernelConfig& config,
1246                ROCmConfigValueTarget target, uint64_t value)
1247{
1248    switch(target)
1249    {
1250        case ROCMCVAL_SGPRSNUM:
1251            config.usedSGPRsNum = value;
1252            break;
1253        case ROCMCVAL_VGPRSNUM:
1254            config.usedVGPRsNum = value;
1255            break;
1256        case ROCMCVAL_PGMRSRC1:
1257            config.computePgmRsrc1 = value;
1258            break;
1259        case ROCMCVAL_PGMRSRC2:
1260            config.computePgmRsrc2 = value;
1261            break;
1262        case ROCMCVAL_FLOATMODE:
1263            config.floatMode = value;
1264            break;
1265        case ROCMCVAL_PRIORITY:
1266            config.priority = value;
1267            break;
1268        case ROCMCVAL_USERDATANUM:
1269            config.userDataNum = value;
1270            break;
1271        case ROCMCVAL_EXCEPTIONS:
1272            config.exceptions = value;
1273            break;
1274        case ROCMCVAL_KERNEL_CODE_ENTRY_OFFSET:
1275            config.kernelCodeEntryOffset = value;
1276            break;
1277        case ROCMCVAL_KERNEL_CODE_PREFETCH_OFFSET:
1278            config.kernelCodePrefetchOffset = value;
1279            break;
1280        case ROCMCVAL_KERNEL_CODE_PREFETCH_SIZE:
1281            config.kernelCodePrefetchSize = value;
1282            break;
1283        case ROCMCVAL_MAX_SCRATCH_BACKING_MEMORY:
1284            config.maxScrachBackingMemorySize = value;
1285            break;
1286        case ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE:
1287            config.workitemPrivateSegmentSize = value;
1288            break;
1289        case ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE:
1290            config.workgroupGroupSegmentSize = value;
1291            break;
1292        case ROCMCVAL_GDS_SEGMENT_SIZE:
1293            config.gdsSegmentSize = value;
1294            break;
1295        case ROCMCVAL_KERNARG_SEGMENT_SIZE:
1296            config.kernargSegmentSize = value;
1297            break;
1298        case ROCMCVAL_WORKGROUP_FBARRIER_COUNT:
1299            config.workgroupFbarrierCount = value;
1300            break;
1301        case ROCMCVAL_WAVEFRONT_SGPR_COUNT:
1302            config.wavefrontSgprCount = value;
1303            break;
1304        case ROCMCVAL_WORKITEM_VGPR_COUNT:
1305            config.workitemVgprCount = value;
1306            break;
1307        case ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1308            config.debugWavefrontPrivateSegmentOffsetSgpr = value;
1309            break;
1310        case ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1311            config.debugPrivateSegmentBufferSgpr = value;
1312            break;
1313        case ROCMCVAL_PRIVATE_ELEM_SIZE:
1314            config.enableFeatureFlags = (config.enableFeatureFlags & ~6) |
1315                    ((63-CLZ64(value)-1)<<1);
1316            break;
1317        case ROCMCVAL_KERNARG_SEGMENT_ALIGN:
1318            config.kernargSegmentAlignment = 63-CLZ64(value);
1319            break;
1320        case ROCMCVAL_GROUP_SEGMENT_ALIGN:
1321            config.groupSegmentAlignment = 63-CLZ64(value);
1322            break;
1323        case ROCMCVAL_PRIVATE_SEGMENT_ALIGN:
1324            config.privateSegmentAlignment = 63-CLZ64(value);
1325            break;
1326        case ROCMCVAL_WAVEFRONT_SIZE:
1327            config.wavefrontSize = 63-CLZ64(value);
1328            break;
1329        case ROCMCVAL_CALL_CONVENTION:
1330            config.callConvention = value;
1331            break;
1332        case ROCMCVAL_RUNTIME_LOADER_KERNEL_SYMBOL:
1333            config.runtimeLoaderKernelSymbol = value;
1334            break;
1335        default:
1336            break;
1337    }
1338}
1339
1340/// set metadata config values
1341void AsmROCmPseudoOps::setMDConfigValue(ROCmKernelMetadata& metadata,
1342                        ROCmConfigValueTarget target, uint64_t value)
1343{
1344    switch(target)
1345    {
1346        case ROCMCVAL_MD_WAVEFRONT_SIZE:
1347            metadata.wavefrontSize = value;
1348            break;
1349        case ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN:
1350            metadata.kernargSegmentAlign = value;
1351            break;
1352        case ROCMCVAL_MD_KERNARG_SEGMENT_SIZE:
1353            metadata.kernargSegmentSize = value;
1354            break;
1355        case ROCMCVAL_MD_GROUP_SEGMENT_FIXED_SIZE:
1356            metadata.groupSegmentFixedSize = value;
1357            break;
1358        case ROCMCVAL_MD_PRIVATE_SEGMENT_FIXED_SIZE:
1359            metadata.privateSegmentFixedSize = value;
1360            break;
1361        case ROCMCVAL_MD_SGPRSNUM:
1362            metadata.sgprsNum = value;
1363            break;
1364        case ROCMCVAL_MD_VGPRSNUM:
1365            metadata.vgprsNum = value;
1366            break;
1367        case ROCMCVAL_MD_SPILLEDSGPRS:
1368            metadata.spilledSgprs = value;
1369            break;
1370        case ROCMCVAL_MD_SPILLEDVGPRS:
1371            metadata.spilledVgprs = value;
1372            break;
1373        case ROCMCVAL_MAX_FLAT_WORK_GROUP_SIZE:
1374            metadata.maxFlatWorkGroupSize = value;
1375            break;
1376        default:
1377            break;
1378    }
1379}
1380
1381void AsmROCmPseudoOps::setConfigValue(AsmROCmHandler& handler, const char* pseudoOpPlace,
1382                  const char* linePtr, ROCmConfigValueTarget target)
1383{
1384    Assembler& asmr = handler.assembler;
1385    const char* end = asmr.line + asmr.lineSize;
1386   
1387    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1388        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1389        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1390   
1391    skipSpacesToEnd(linePtr, end);
1392    const char* valuePlace = linePtr;
1393    uint64_t value = BINGEN64_NOTSUPPLIED;
1394    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
1395    /* ranges checking */
1396    if (good)
1397    {
1398        if (target < ROCMCVAL_METADATA_START)
1399            good = checkConfigValue(asmr, valuePlace, target, value);
1400        else // metadata values
1401            good = checkMDConfigValue(asmr, valuePlace, target, value);
1402    }
1403    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1404        return;
1405   
1406    // set value
1407    if (target < ROCMCVAL_METADATA_START)
1408    {
1409        AsmROCmKernelConfig& config = *(handler.kernelStates[asmr.currentKernel]->config);
1410        setConfigValueMain(config, target, value);
1411    }
1412    else
1413    {
1414        // set metadata value
1415        handler.output.useMetadataInfo = true;
1416        ROCmKernelMetadata& metadata = 
1417                    handler.output.metadataInfo.kernels[asmr.currentKernel];
1418        setMDConfigValue(metadata, target, value);
1419    }
1420}
1421
1422void AsmROCmPseudoOps::setConfigBoolValueMain(AsmAmdHsaKernelConfig& config,
1423                ROCmConfigValueTarget target)
1424{
1425    switch(target)
1426    {
1427        case ROCMCVAL_PRIVMODE:
1428            config.privilegedMode = true;
1429            break;
1430        case ROCMCVAL_DEBUGMODE:
1431            config.debugMode = true;
1432            break;
1433        case ROCMCVAL_DX10CLAMP:
1434            config.dx10Clamp = true;
1435            break;
1436        case ROCMCVAL_IEEEMODE:
1437            config.ieeeMode = true;
1438            break;
1439        case ROCMCVAL_TGSIZE:
1440            config.tgSize = true;
1441            break;
1442        case ROCMCVAL_USE_PRIVATE_SEGMENT_BUFFER:
1443            config.enableSgprRegisterFlags |= ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER;
1444            break;
1445        case ROCMCVAL_USE_DISPATCH_PTR:
1446            config.enableSgprRegisterFlags |= ROCMFLAG_USE_DISPATCH_PTR;
1447            break;
1448        case ROCMCVAL_USE_QUEUE_PTR:
1449            config.enableSgprRegisterFlags |= ROCMFLAG_USE_QUEUE_PTR;
1450            break;
1451        case ROCMCVAL_USE_KERNARG_SEGMENT_PTR:
1452            config.enableSgprRegisterFlags |= ROCMFLAG_USE_KERNARG_SEGMENT_PTR;
1453            break;
1454        case ROCMCVAL_USE_DISPATCH_ID:
1455            config.enableSgprRegisterFlags |= ROCMFLAG_USE_DISPATCH_ID;
1456            break;
1457        case ROCMCVAL_USE_FLAT_SCRATCH_INIT:
1458            config.enableSgprRegisterFlags |= ROCMFLAG_USE_FLAT_SCRATCH_INIT;
1459            break;
1460        case ROCMCVAL_USE_PRIVATE_SEGMENT_SIZE:
1461            config.enableSgprRegisterFlags |= ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE;
1462            break;
1463        case ROCMCVAL_USE_ORDERED_APPEND_GDS:
1464            config.enableFeatureFlags |= ROCMFLAG_USE_ORDERED_APPEND_GDS;
1465            break;
1466        case ROCMCVAL_USE_PTR64:
1467            config.enableFeatureFlags |= ROCMFLAG_USE_PTR64;
1468            break;
1469        case ROCMCVAL_USE_DYNAMIC_CALL_STACK:
1470            config.enableFeatureFlags |= ROCMFLAG_USE_DYNAMIC_CALL_STACK;
1471            break;
1472        case ROCMCVAL_USE_DEBUG_ENABLED:
1473            config.enableFeatureFlags |= ROCMFLAG_USE_DEBUG_ENABLED;
1474            break;
1475        case ROCMCVAL_USE_XNACK_ENABLED:
1476            config.enableFeatureFlags |= ROCMFLAG_USE_XNACK_ENABLED;
1477            break;
1478        default:
1479            break;
1480    }
1481}
1482
1483void AsmROCmPseudoOps::setConfigBoolValue(AsmROCmHandler& handler,
1484          const char* pseudoOpPlace, const char* linePtr, ROCmConfigValueTarget target)
1485{
1486    Assembler& asmr = handler.assembler;
1487    const char* end = asmr.line + asmr.lineSize;
1488   
1489    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1490        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1491        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1492   
1493    skipSpacesToEnd(linePtr, end);
1494    if (!checkGarbagesAtEnd(asmr, linePtr))
1495        return;
1496   
1497    AsmROCmKernelConfig& config = *(handler.kernelStates[asmr.currentKernel]->config);
1498   
1499    setConfigBoolValueMain(config, target);
1500}
1501
1502void AsmROCmPseudoOps::setDefaultHSAFeatures(AsmROCmHandler& handler,
1503                    const char* pseudoOpPlace, const char* linePtr)
1504{
1505    Assembler& asmr = handler.assembler;
1506   
1507    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1508        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1509        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1510   
1511    if (!checkGarbagesAtEnd(asmr, linePtr))
1512        return;
1513   
1514    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1515    config->enableSgprRegisterFlags = uint16_t(ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER|
1516                    ROCMFLAG_USE_DISPATCH_PTR|ROCMFLAG_USE_KERNARG_SEGMENT_PTR);
1517    config->enableFeatureFlags = uint16_t(AMDHSAFLAG_USE_PTR64|2);
1518}
1519
1520void AsmROCmPseudoOps::setDimensions(AsmROCmHandler& handler, const char* pseudoOpPlace,
1521                  const char* linePtr)
1522{
1523    Assembler& asmr = handler.assembler;
1524    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1525        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1526        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1527    cxuint dimMask = 0;
1528    if (!parseDimensions(asmr, linePtr, dimMask))
1529        return;
1530    if (!checkGarbagesAtEnd(asmr, linePtr))
1531        return;
1532    handler.kernelStates[asmr.currentKernel]->config->dimMask = dimMask;
1533}
1534
1535// parse machine version - used also in AsmGalliumFormat
1536// four numbers - kind, major, minor, stepping
1537bool AsmROCmPseudoOps::parseMachine(Assembler& asmr, const char* linePtr,
1538        uint16_t& machineKind, uint16_t& machineMajor, uint16_t& machineMinor,
1539        uint16_t& machineStepping)
1540{
1541    const char* end = asmr.line + asmr.lineSize;
1542   
1543    skipSpacesToEnd(linePtr, end);
1544    uint64_t kindValue = 0;
1545    uint64_t majorValue = 0;
1546    uint64_t minorValue = 0;
1547    uint64_t steppingValue = 0;
1548    const char* valuePlace = linePtr;
1549    bool good = getAbsoluteValueArg(asmr, kindValue, linePtr, true);
1550    // parse kind
1551    asmr.printWarningForRange(16, kindValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1552    if (!skipRequiredComma(asmr, linePtr))
1553        return false;
1554   
1555    valuePlace = linePtr;
1556    good &= getAbsoluteValueArg(asmr, majorValue, linePtr, true);
1557    // parse major
1558    asmr.printWarningForRange(16, majorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1559    if (!skipRequiredComma(asmr, linePtr))
1560        return false;
1561   
1562    valuePlace = linePtr;
1563    good &= getAbsoluteValueArg(asmr, minorValue, linePtr, true);
1564    // parse minor
1565    asmr.printWarningForRange(16, minorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1566    if (!skipRequiredComma(asmr, linePtr))
1567        return false;
1568   
1569    valuePlace = linePtr;
1570    // parse stepping
1571    good &= getAbsoluteValueArg(asmr, steppingValue, linePtr, true);
1572    asmr.printWarningForRange(16, steppingValue,
1573                      asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1574   
1575    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1576        return false;
1577   
1578    machineKind = kindValue;
1579    machineMajor = majorValue;
1580    machineMinor = minorValue;
1581    machineStepping = steppingValue;
1582    return true;
1583}
1584
1585// set machine - four numbers - kind, major, minor, stepping
1586void AsmROCmPseudoOps::setMachine(AsmROCmHandler& handler, const char* pseudoOpPlace,
1587                      const char* linePtr)
1588{
1589    Assembler& asmr = handler.assembler;
1590    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1591        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1592        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1593   
1594    uint16_t kindValue = 0, majorValue = 0;
1595    uint16_t minorValue = 0, steppingValue = 0;
1596    if (!parseMachine(asmr, linePtr, kindValue, majorValue, minorValue, steppingValue))
1597        return;
1598   
1599    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1600    config->amdMachineKind = kindValue;
1601    config->amdMachineMajor = majorValue;
1602    config->amdMachineMinor = minorValue;
1603    config->amdMachineStepping = steppingValue;
1604}
1605
1606// parse code version (amd code version) - used also in AsmGalliumFormat
1607// two numbers - major and minor
1608bool AsmROCmPseudoOps::parseCodeVersion(Assembler& asmr, const char* linePtr,
1609                uint16_t& codeMajor, uint16_t& codeMinor)
1610{
1611    const char* end = asmr.line + asmr.lineSize;
1612   
1613    skipSpacesToEnd(linePtr, end);
1614    uint64_t majorValue = 0;
1615    uint64_t minorValue = 0;
1616    const char* valuePlace = linePtr;
1617    // parse version major
1618    bool good = getAbsoluteValueArg(asmr, majorValue, linePtr, true);
1619    asmr.printWarningForRange(32, majorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1620    if (!skipRequiredComma(asmr, linePtr))
1621        return false;
1622   
1623    valuePlace = linePtr;
1624    // parse version minor
1625    good &= getAbsoluteValueArg(asmr, minorValue, linePtr, true);
1626    asmr.printWarningForRange(32, minorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1627   
1628    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1629        return false;
1630   
1631    codeMajor = majorValue;
1632    codeMinor = minorValue;
1633    return true;
1634}
1635
1636// two numbers - major and minor
1637void AsmROCmPseudoOps::setCodeVersion(AsmROCmHandler& handler, const char* pseudoOpPlace,
1638                  const char* linePtr)
1639{
1640    Assembler& asmr = handler.assembler;
1641    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1642        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1643        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1644   
1645    uint16_t majorValue = 0, minorValue = 0;
1646    if (!parseCodeVersion(asmr, linePtr, majorValue, minorValue))
1647        return;
1648   
1649    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1650    config->amdCodeVersionMajor = majorValue;
1651    config->amdCodeVersionMinor = minorValue;
1652}
1653
1654// parse reserved gprs - used also in AsmGalliumFormat
1655// parsereserved S/VGRPS - first number is first register, second is last register
1656bool AsmROCmPseudoOps::parseReservedXgprs(Assembler& asmr, const char* linePtr,
1657                bool inVgpr, uint16_t& gprFirst, uint16_t& gprCount)
1658{
1659    const char* end = asmr.line + asmr.lineSize;
1660    skipSpacesToEnd(linePtr, end);
1661    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(asmr.deviceType);
1662    cxuint maxGPRsNum = getGPUMaxRegistersNum(arch,
1663                       inVgpr ? REGTYPE_VGPR : REGTYPE_SGPR, 0);
1664   
1665    uint64_t firstReg = BINGEN_NOTSUPPLIED;
1666    uint64_t lastReg = BINGEN_NOTSUPPLIED;
1667    const char* valuePlace = linePtr;
1668    bool haveFirstReg;
1669    bool good = getAbsoluteValueArg(asmr, firstReg, linePtr, true);
1670    haveFirstReg = good;
1671    if (haveFirstReg && firstReg > maxGPRsNum-1)
1672    {
1673        // first register is out of range
1674        char buf[64];
1675        snprintf(buf, 64, "First reserved %s register out of range (0-%u)",
1676                 inVgpr ? "VGPR" : "SGPR",  maxGPRsNum-1);
1677        ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1678    }
1679    if (!skipRequiredComma(asmr, linePtr))
1680        return false;
1681   
1682    valuePlace = linePtr;
1683    bool haveLastReg = getAbsoluteValueArg(asmr, lastReg, linePtr, true);
1684    good &= haveLastReg;
1685    if (haveLastReg && lastReg > maxGPRsNum-1)
1686    {
1687        // if last register out of range
1688        char buf[64];
1689        snprintf(buf, 64, "Last reserved %s register out of range (0-%u)",
1690                 inVgpr ? "VGPR" : "SGPR", maxGPRsNum-1);
1691        ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1692    }
1693    if (haveFirstReg && haveLastReg && firstReg > lastReg)
1694        ASM_NOTGOOD_BY_ERROR(valuePlace, "Wrong register range")
1695   
1696    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1697        return false;
1698   
1699    gprFirst = firstReg;
1700    gprCount = lastReg-firstReg+1;
1701    return true;
1702}
1703
1704/// set reserved S/VGRPS - first number is first register, second is last register
1705void AsmROCmPseudoOps::setReservedXgprs(AsmROCmHandler& handler, const char* pseudoOpPlace,
1706                      const char* linePtr, bool inVgpr)
1707{
1708    Assembler& asmr = handler.assembler;
1709    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1710        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1711        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1712   
1713    uint16_t gprFirst = 0, gprCount = 0;
1714    if (!parseReservedXgprs(asmr, linePtr, inVgpr, gprFirst, gprCount))
1715        return;
1716   
1717    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1718    if (inVgpr)
1719    {
1720        config->reservedVgprFirst = gprFirst;
1721        config->reservedVgprCount = gprCount;
1722    }
1723    else
1724    {
1725        config->reservedSgprFirst = gprFirst;
1726        config->reservedSgprCount = gprCount;
1727    }
1728}
1729
1730// set UseGridWorkGroupCount - 3 bits for dimensions
1731void AsmROCmPseudoOps::setUseGridWorkGroupCount(AsmROCmHandler& handler,
1732                   const char* pseudoOpPlace, const char* linePtr)
1733{
1734    Assembler& asmr = handler.assembler;
1735    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1736        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1737        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1738    cxuint dimMask = 0;
1739    if (!parseDimensions(asmr, linePtr, dimMask))
1740        return;
1741    if (!checkGarbagesAtEnd(asmr, linePtr))
1742        return;
1743    uint16_t& flags = handler.kernelStates[asmr.currentKernel]->config->
1744                enableSgprRegisterFlags;
1745    flags = (flags & ~(7<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT)) |
1746            (dimMask<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT);
1747}
1748
1749void AsmROCmPseudoOps::updateKCodeSel(AsmROCmHandler& handler,
1750                  const std::vector<cxuint>& oldset)
1751{
1752    Assembler& asmr = handler.assembler;
1753    // old elements - join current regstate with all them
1754    size_t regTypesNum;
1755    for (auto it = oldset.begin(); it != oldset.end(); ++it)
1756    {
1757        Flags curAllocRegFlags;
1758        const cxuint* curAllocRegs = asmr.isaAssembler->getAllocatedRegisters(regTypesNum,
1759                               curAllocRegFlags);
1760        cxuint newAllocRegs[MAX_REGTYPES_NUM];
1761        AsmROCmHandler::Kernel& kernel = *(handler.kernelStates[*it]);
1762        for (size_t i = 0; i < regTypesNum; i++)
1763            newAllocRegs[i] = std::max(curAllocRegs[i], kernel.allocRegs[i]);
1764        kernel.allocRegFlags |= curAllocRegFlags;
1765        std::copy(newAllocRegs, newAllocRegs+regTypesNum, kernel.allocRegs);
1766    }
1767    asmr.isaAssembler->setAllocatedRegisters();
1768}
1769
1770void AsmROCmPseudoOps::doKCode(AsmROCmHandler& handler, const char* pseudoOpPlace,
1771                  const char* linePtr)
1772{
1773    Assembler& asmr = handler.assembler;
1774    const char* end = asmr.line + asmr.lineSize;
1775    bool good = true;
1776    skipSpacesToEnd(linePtr, end);
1777    if (linePtr==end)
1778        return;
1779    std::unordered_set<cxuint> newSel(handler.kcodeSelection.begin(),
1780                          handler.kcodeSelection.end());
1781    do {
1782        CString kname;
1783        const char* knamePlace = linePtr;
1784        skipSpacesToEnd(linePtr, end);
1785        bool removeKernel = false;
1786        if (linePtr!=end && *linePtr=='-')
1787        {
1788            // '-' - remove this kernel from current kernel selection
1789            removeKernel = true;
1790            linePtr++;
1791        }
1792        else if (linePtr!=end && *linePtr=='+')
1793        {
1794            linePtr++;
1795            skipSpacesToEnd(linePtr, end);
1796            if (linePtr==end)
1797            {
1798                // add all kernels
1799                for (cxuint k = 0; k < handler.kernelStates.size(); k++)
1800                    newSel.insert(k);
1801                break;
1802            }
1803        }
1804       
1805        if (!getNameArg(asmr, kname, linePtr, "kernel"))
1806        { good = false; continue; }
1807        auto kit = asmr.kernelMap.find(kname);
1808        if (kit == asmr.kernelMap.end())
1809        {
1810            asmr.printError(knamePlace, "Kernel not found");
1811            continue;
1812        }
1813        if (!removeKernel)
1814            newSel.insert(kit->second);
1815        else // remove kernel
1816            newSel.erase(kit->second);
1817    } while (skipCommaForMultipleArgs(asmr, linePtr));
1818   
1819    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1820        return;
1821   
1822    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
1823        PSEUDOOP_RETURN_BY_ERROR("KCode outside code")
1824    if (handler.kcodeSelStack.empty())
1825        handler.saveKcodeCurrentAllocRegs();
1826    // push to stack
1827    handler.kcodeSelStack.push(handler.kcodeSelection);
1828    // set current sel
1829    handler.kcodeSelection.assign(newSel.begin(), newSel.end());
1830    std::sort(handler.kcodeSelection.begin(), handler.kcodeSelection.end());
1831   
1832    const std::vector<cxuint>& oldKCodeSel = handler.kcodeSelStack.top();
1833    if (!oldKCodeSel.empty())
1834        asmr.handleRegionsOnKernels(handler.kcodeSelection, oldKCodeSel,
1835                            handler.codeSection);
1836    else if (handler.currentKcodeKernel != ASMKERN_GLOBAL)
1837    {
1838        std::vector<cxuint> tempKCodeSel;
1839        tempKCodeSel.push_back(handler.currentKcodeKernel);
1840        asmr.handleRegionsOnKernels(handler.kcodeSelection, tempKCodeSel,
1841                            handler.codeSection);
1842    }
1843   
1844    updateKCodeSel(handler, handler.kcodeSelStack.top());
1845}
1846
1847void AsmROCmPseudoOps::doKCodeEnd(AsmROCmHandler& handler, const char* pseudoOpPlace,
1848                  const char* linePtr)
1849{
1850    Assembler& asmr = handler.assembler;
1851    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
1852        PSEUDOOP_RETURN_BY_ERROR("KCodeEnd outside code")
1853    if (handler.kcodeSelStack.empty())
1854        PSEUDOOP_RETURN_BY_ERROR("'.kcodeend' without '.kcode'")
1855    if (!checkGarbagesAtEnd(asmr, linePtr))
1856        return;
1857   
1858    updateKCodeSel(handler, handler.kcodeSelection);
1859    std::vector<cxuint> oldKCodeSel = handler.kcodeSelection;
1860    handler.kcodeSelection = handler.kcodeSelStack.top();
1861   
1862    if (!handler.kcodeSelection.empty())
1863        asmr.handleRegionsOnKernels(handler.kcodeSelection, oldKCodeSel,
1864                        handler.codeSection);
1865    else if (handler.currentKcodeKernel != ASMKERN_GLOBAL)
1866    {
1867        // if choosen current kernel
1868        std::vector<cxuint> curKernelSel;
1869        curKernelSel.push_back(handler.currentKcodeKernel);
1870        asmr.handleRegionsOnKernels(curKernelSel, oldKCodeSel, handler.codeSection);
1871    }
1872   
1873    handler.kcodeSelStack.pop();
1874    if (handler.kcodeSelStack.empty())
1875        handler.restoreKcodeCurrentAllocRegs();
1876}
1877
1878}
1879
1880bool AsmROCmHandler::parsePseudoOp(const CString& firstName, const char* stmtPlace,
1881               const char* linePtr)
1882{
1883    const size_t pseudoOp = binaryFind(rocmPseudoOpNamesTbl, rocmPseudoOpNamesTbl +
1884                    sizeof(rocmPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
1885                   CStringLess()) - rocmPseudoOpNamesTbl;
1886   
1887    switch(pseudoOp)
1888    {
1889        case ROCMOP_ARCH_MINOR:
1890            AsmROCmPseudoOps::setArchMinor(*this, linePtr);
1891            break;
1892        case ROCMOP_ARCH_STEPPING:
1893            AsmROCmPseudoOps::setArchStepping(*this, linePtr);
1894            break;
1895        case ROCMOP_ARG:
1896            AsmROCmPseudoOps::addKernelArg(*this, stmtPlace, linePtr);
1897            break;
1898        case ROCMOP_CALL_CONVENTION:
1899            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1900                             ROCMCVAL_CALL_CONVENTION);
1901            break;
1902        case ROCMOP_CODEVERSION:
1903            AsmROCmPseudoOps::setCodeVersion(*this, stmtPlace, linePtr);
1904            break;
1905        case ROCMOP_CONFIG:
1906            AsmROCmPseudoOps::doConfig(*this, stmtPlace, linePtr);
1907            break;
1908        case ROCMOP_CONTROL_DIRECTIVE:
1909            AsmROCmPseudoOps::doControlDirective(*this, stmtPlace, linePtr);
1910            break;
1911        case ROCMOP_CWS:
1912        case ROCMOP_REQD_WORK_GROUP_SIZE:
1913            AsmROCmPseudoOps::setCWS(*this, stmtPlace, linePtr);
1914            break;
1915        case ROCMOP_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1916            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1917                             ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR);
1918            break;
1919        case ROCMOP_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1920            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1921                         ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR);
1922            break;
1923        case ROCMOP_DEBUGMODE:
1924            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1925                             ROCMCVAL_DEBUGMODE);
1926            break;
1927        case ROCMOP_DIMS:
1928            AsmROCmPseudoOps::setDimensions(*this, stmtPlace, linePtr);
1929            break;
1930        case ROCMOP_DX10CLAMP:
1931            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1932                             ROCMCVAL_DX10CLAMP);
1933            break;
1934        case ROCMOP_EFLAGS:
1935            AsmROCmPseudoOps::setEFlags(*this, linePtr);
1936            break;
1937        case ROCMOP_EXCEPTIONS:
1938            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1939                             ROCMCVAL_EXCEPTIONS);
1940            break;
1941        case ROCMOP_FIXED_WORK_GROUP_SIZE:
1942            AsmROCmPseudoOps::setFixedWorkGroupSize(*this, stmtPlace, linePtr);
1943            break;
1944        case ROCMOP_FKERNEL:
1945            AsmROCmPseudoOps::doFKernel(*this, stmtPlace, linePtr);
1946            break;
1947        case ROCMOP_FLOATMODE:
1948            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1949                             ROCMCVAL_FLOATMODE);
1950            break;
1951        case ROCMOP_GLOBALDATA:
1952            AsmROCmPseudoOps::doGlobalData(*this, stmtPlace, linePtr);
1953            break;
1954        case ROCMOP_GDS_SEGMENT_SIZE:
1955            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1956                             ROCMCVAL_GDS_SEGMENT_SIZE);
1957            break;
1958        case ROCMOP_GROUP_SEGMENT_ALIGN:
1959            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1960                             ROCMCVAL_GROUP_SEGMENT_ALIGN);
1961            break;
1962        case ROCMOP_DEFAULT_HSA_FEATURES:
1963            AsmROCmPseudoOps::setDefaultHSAFeatures(*this, stmtPlace, linePtr);
1964            break;
1965        case ROCMOP_IEEEMODE:
1966            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1967                             ROCMCVAL_IEEEMODE);
1968            break;
1969        case ROCMOP_KCODE:
1970            AsmROCmPseudoOps::doKCode(*this, stmtPlace, linePtr);
1971            break;
1972        case ROCMOP_KCODEEND:
1973            AsmROCmPseudoOps::doKCodeEnd(*this, stmtPlace, linePtr);
1974            break;
1975        case ROCMOP_KERNARG_SEGMENT_ALIGN:
1976            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1977                             ROCMCVAL_KERNARG_SEGMENT_ALIGN);
1978            break;
1979        case ROCMOP_KERNARG_SEGMENT_SIZE:
1980            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1981                             ROCMCVAL_KERNARG_SEGMENT_SIZE);
1982            break;
1983        case ROCMOP_KERNEL_CODE_ENTRY_OFFSET:
1984            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1985                             ROCMCVAL_KERNEL_CODE_ENTRY_OFFSET);
1986            break;
1987        case ROCMOP_KERNEL_CODE_PREFETCH_OFFSET:
1988            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1989                             ROCMCVAL_KERNEL_CODE_PREFETCH_OFFSET);
1990            break;
1991        case ROCMOP_KERNEL_CODE_PREFETCH_SIZE:
1992            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1993                             ROCMCVAL_KERNEL_CODE_PREFETCH_SIZE);
1994            break;
1995        case ROCMOP_LOCALSIZE:
1996            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1997                             ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE);
1998            break;
1999        case ROCMOP_MACHINE:
2000            AsmROCmPseudoOps::setMachine(*this, stmtPlace, linePtr);
2001            break;
2002        case ROCMOP_MAX_FLAT_WORK_GROUP_SIZE:
2003            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2004                            ROCMCVAL_MAX_FLAT_WORK_GROUP_SIZE);
2005            break;
2006        case ROCMOP_MAX_SCRATCH_BACKING_MEMORY:
2007            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2008                             ROCMCVAL_MAX_SCRATCH_BACKING_MEMORY);
2009            break;
2010        case ROCMOP_METADATA:
2011            AsmROCmPseudoOps::addMetadata(*this, stmtPlace, linePtr);
2012            break;
2013        case ROCMOP_MD_GROUP_SEGMENT_FIXED_SIZE:
2014            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2015                            ROCMCVAL_MD_GROUP_SEGMENT_FIXED_SIZE);
2016            break;
2017        case ROCMOP_MD_KERNARG_SEGMENT_ALIGN:
2018            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2019                            ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN);
2020            break;
2021        case ROCMOP_MD_KERNARG_SEGMENT_SIZE:
2022            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2023                            ROCMCVAL_MD_KERNARG_SEGMENT_SIZE);
2024            break;
2025        case ROCMOP_MD_LANGUAGE:
2026            AsmROCmPseudoOps::setKernelLanguage(*this, stmtPlace, linePtr);
2027            break;
2028        case ROCMOP_MD_PRIVATE_SEGMENT_FIXED_SIZE:
2029            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2030                            ROCMCVAL_MD_PRIVATE_SEGMENT_FIXED_SIZE);
2031            break;
2032        case ROCMOP_SPILLEDSGPRS:
2033            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2034                            ROCMCVAL_MD_SPILLEDSGPRS);
2035            break;
2036        case ROCMOP_SPILLEDVGPRS:
2037            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2038                            ROCMCVAL_MD_SPILLEDVGPRS);
2039            break;
2040        case ROCMOP_MD_SGPRSNUM:
2041            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2042                            ROCMCVAL_MD_SGPRSNUM);
2043            break;
2044        case ROCMOP_MD_SYMNAME:
2045            AsmROCmPseudoOps::setKernelSymName(*this, stmtPlace, linePtr);
2046            break;
2047        case ROCMOP_MD_VERSION:
2048            AsmROCmPseudoOps::setMetadataVersion(*this, stmtPlace, linePtr);
2049            break;
2050        case ROCMOP_MD_VGPRSNUM:
2051            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2052                            ROCMCVAL_MD_VGPRSNUM);
2053            break;
2054        case ROCMOP_MD_WAVEFRONT_SIZE:
2055            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2056                            ROCMCVAL_MD_WAVEFRONT_SIZE);
2057            break;
2058        case ROCMOP_NEWBINFMT:
2059            AsmROCmPseudoOps::setNewBinFormat(*this, linePtr);
2060            break;
2061        case ROCMOP_PGMRSRC1:
2062            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PGMRSRC1);
2063            break;
2064        case ROCMOP_PGMRSRC2:
2065            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PGMRSRC2);
2066            break;
2067        case ROCMOP_PRINTF:
2068            AsmROCmPseudoOps::addPrintf(*this, stmtPlace, linePtr);
2069            break;
2070        case ROCMOP_PRIORITY:
2071            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PRIORITY);
2072            break;
2073        case ROCMOP_PRIVATE_ELEM_SIZE:
2074            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2075                             ROCMCVAL_PRIVATE_ELEM_SIZE);
2076            break;
2077        case ROCMOP_PRIVATE_SEGMENT_ALIGN:
2078            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2079                             ROCMCVAL_PRIVATE_SEGMENT_ALIGN);
2080            break;
2081        case ROCMOP_PRIVMODE:
2082            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2083                             ROCMCVAL_PRIVMODE);
2084            break;
2085        case ROCMOP_RESERVED_SGPRS:
2086            AsmROCmPseudoOps::setReservedXgprs(*this, stmtPlace, linePtr, false);
2087            break;
2088        case ROCMOP_RESERVED_VGPRS:
2089            AsmROCmPseudoOps::setReservedXgprs(*this, stmtPlace, linePtr, true);
2090            break;
2091        case ROCMOP_RUNTIME_HANDLE:
2092            AsmROCmPseudoOps::setRuntimeHandle(*this, stmtPlace, linePtr);
2093            break;
2094        case ROCMOP_RUNTIME_LOADER_KERNEL_SYMBOL:
2095            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2096                             ROCMCVAL_RUNTIME_LOADER_KERNEL_SYMBOL);
2097            break;
2098        case ROCMOP_SCRATCHBUFFER:
2099            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2100                             ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE);
2101            break;
2102        case ROCMOP_SGPRSNUM:
2103            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2104                             ROCMCVAL_SGPRSNUM);
2105            break;
2106        case ROCMOP_TARGET:
2107            AsmROCmPseudoOps::setTarget(*this, linePtr, false);
2108            break;
2109        case ROCMOP_TGSIZE:
2110            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2111                             ROCMCVAL_TGSIZE);
2112            break;
2113        case ROCMOP_TRIPPLE:
2114            AsmROCmPseudoOps::setTarget(*this, linePtr, true);
2115            break;
2116        case ROCMOP_USE_DEBUG_ENABLED:
2117            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2118                             ROCMCVAL_USE_DEBUG_ENABLED);
2119            break;
2120        case ROCMOP_USE_DISPATCH_ID:
2121            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2122                             ROCMCVAL_USE_DISPATCH_ID);
2123            break;
2124        case ROCMOP_USE_DISPATCH_PTR:
2125            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2126                             ROCMCVAL_USE_DISPATCH_PTR);
2127            break;
2128        case ROCMOP_USE_DYNAMIC_CALL_STACK:
2129            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2130                             ROCMCVAL_USE_DYNAMIC_CALL_STACK);
2131            break;
2132        case ROCMOP_USE_FLAT_SCRATCH_INIT:
2133            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2134                             ROCMCVAL_USE_FLAT_SCRATCH_INIT);
2135            break;
2136        case ROCMOP_USE_GRID_WORKGROUP_COUNT:
2137            AsmROCmPseudoOps::setUseGridWorkGroupCount(*this, stmtPlace, linePtr);
2138            break;
2139        case ROCMOP_USE_KERNARG_SEGMENT_PTR:
2140            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2141                             ROCMCVAL_USE_KERNARG_SEGMENT_PTR);
2142            break;
2143        case ROCMOP_USE_ORDERED_APPEND_GDS:
2144            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2145                             ROCMCVAL_USE_ORDERED_APPEND_GDS);
2146            break;
2147        case ROCMOP_USE_PRIVATE_SEGMENT_SIZE:
2148            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2149                             ROCMCVAL_USE_PRIVATE_SEGMENT_SIZE);
2150            break;
2151        case ROCMOP_USE_PTR64:
2152            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2153                             ROCMCVAL_USE_PTR64);
2154            break;
2155        case ROCMOP_USE_QUEUE_PTR:
2156            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2157                             ROCMCVAL_USE_QUEUE_PTR);
2158            break;
2159        case ROCMOP_USE_PRIVATE_SEGMENT_BUFFER:
2160            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2161                             ROCMCVAL_USE_PRIVATE_SEGMENT_BUFFER);
2162            break;
2163        case ROCMOP_USE_XNACK_ENABLED:
2164            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2165                             ROCMCVAL_USE_XNACK_ENABLED);
2166            break;
2167        case ROCMOP_USERDATANUM:
2168            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2169                             ROCMCVAL_USERDATANUM);
2170            break;
2171        case ROCMOP_VECTYPEHINT:
2172            AsmROCmPseudoOps::setVecTypeHint(*this, stmtPlace, linePtr);
2173            break;
2174        case ROCMOP_VGPRSNUM:
2175            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_VGPRSNUM);
2176            break;
2177        case ROCMOP_WAVEFRONT_SGPR_COUNT:
2178            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2179                             ROCMCVAL_WAVEFRONT_SGPR_COUNT);
2180            break;
2181        case ROCMOP_WAVEFRONT_SIZE:
2182            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2183                             ROCMCVAL_WAVEFRONT_SIZE);
2184            break;
2185        case ROCMOP_WORKITEM_VGPR_COUNT:
2186            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2187                             ROCMCVAL_WORKITEM_VGPR_COUNT);
2188            break;
2189        case ROCM_WORK_GROUP_SIZE_HINT:
2190            AsmROCmPseudoOps::setWorkGroupSizeHint(*this, stmtPlace, linePtr);
2191            break;
2192        case ROCMOP_WORKGROUP_FBARRIER_COUNT:
2193            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2194                             ROCMCVAL_WORKGROUP_FBARRIER_COUNT);
2195            break;
2196        case ROCMOP_WORKGROUP_GROUP_SEGMENT_SIZE:
2197            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2198                             ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE);
2199            break;
2200        case ROCMOP_WORKITEM_PRIVATE_SEGMENT_SIZE:
2201            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2202                             ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE);
2203            break;
2204        default:
2205            return false;
2206    }
2207    return true;
2208}
2209
2210bool AsmROCmHandler::prepareBinary()
2211{
2212    bool good = true;
2213    size_t sectionsNum = sections.size();
2214    output.deviceType = assembler.getDeviceType();
2215   
2216    if (assembler.isaAssembler!=nullptr)
2217    {
2218        // make last kernel registers pool updates
2219        if (kcodeSelStack.empty())
2220            saveKcodeCurrentAllocRegs();
2221        else
2222            while (!kcodeSelStack.empty())
2223            {
2224                // pop from kcode stack and apply changes
2225                AsmROCmPseudoOps::updateKCodeSel(*this, kcodeSelection);
2226                kcodeSelection = kcodeSelStack.top();
2227                kcodeSelStack.pop();
2228            }
2229    }
2230   
2231    // set sections as outputs
2232    for (size_t i = 0; i < sectionsNum; i++)
2233    {
2234        const AsmSection& asmSection = assembler.sections[i];
2235        const Section& section = sections[i];
2236        const size_t sectionSize = asmSection.getSize();
2237        const cxbyte* sectionData = (!asmSection.content.empty()) ?
2238                asmSection.content.data() : (const cxbyte*)"";
2239        switch(asmSection.type)
2240        {
2241            case AsmSectionType::CODE:
2242                output.codeSize = sectionSize;
2243                output.code = sectionData;
2244                break;
2245            case AsmSectionType::EXTRA_PROGBITS:
2246            case AsmSectionType::EXTRA_NOTE:
2247            case AsmSectionType::EXTRA_NOBITS:
2248            case AsmSectionType::EXTRA_SECTION:
2249            {
2250                // handle extra (user) section, set section type and its flags
2251                uint32_t elfSectType =
2252                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
2253                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
2254                             SHT_PROGBITS;
2255                uint32_t elfSectFlags = 
2256                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
2257                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
2258                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
2259                output.extraSections.push_back({section.name, sectionSize, sectionData,
2260                    asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
2261                    elfSectFlags, ELFSECTID_NULL, 0, 0 });
2262                break;
2263            }
2264            case AsmSectionType::ROCM_CONFIG_CTRL_DIRECTIVE:
2265                if (sectionSize != 128)
2266                    // control directive accepts only 128-byte size
2267                    assembler.printError(AsmSourcePos(),
2268                         (std::string("Section '.control_directive' for kernel '")+
2269                          assembler.kernels[section.kernelId].name+
2270                          "' have wrong size").c_str());
2271                break;
2272            case AsmSectionType::ROCM_COMMENT:
2273                output.commentSize = sectionSize;
2274                output.comment = (const char*)sectionData;
2275                break;
2276            case AsmSectionType::DATA:
2277                output.globalDataSize = sectionSize;
2278                output.globalData = sectionData;
2279                break;
2280            case AsmSectionType::ROCM_METADATA:
2281                output.metadataSize = sectionSize;
2282                output.metadata = (const char*)sectionData;
2283                break;
2284            default:
2285                break;
2286        }
2287    }
2288   
2289    // enable metadata config for new binary format by default (if no metadata section)
2290    if (output.newBinFormat && output.metadata==nullptr)
2291        output.useMetadataInfo = true;
2292   
2293    GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
2294    // set up number of the allocated SGPRs and VGPRs for kernel
2295    cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
2296   
2297    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(assembler.deviceType,
2298                                GPUArchVersionTable::OPENSOURCE);
2299    // replace arch minor and stepping by user defined values (if set)
2300    if (output.archMinor!=UINT32_MAX)
2301        amdGpuArchValues.minor = output.archMinor;
2302    if (output.archStepping!=UINT32_MAX)
2303        amdGpuArchValues.stepping = output.archStepping;
2304   
2305    // prepare kernels configuration
2306    for (size_t i = 0; i < kernelStates.size(); i++)
2307    {
2308        const Kernel& kernel = *kernelStates[i];
2309        if (kernel.config.get() == nullptr)
2310            continue;
2311        const CString& kernelName = assembler.kernels[i].name;
2312        AsmROCmKernelConfig& config = *kernel.config.get();
2313        // setup config
2314        // fill default values
2315        if (config.amdCodeVersionMajor == BINGEN_DEFAULT)
2316            config.amdCodeVersionMajor = 1;
2317        if (config.amdCodeVersionMinor == BINGEN_DEFAULT)
2318            config.amdCodeVersionMinor = 0;
2319        if (config.amdMachineKind == BINGEN16_DEFAULT)
2320            config.amdMachineKind = 1;
2321        if (config.amdMachineMajor == BINGEN16_DEFAULT)
2322            config.amdMachineMajor = amdGpuArchValues.major;
2323        if (config.amdMachineMinor == BINGEN16_DEFAULT)
2324            config.amdMachineMinor = amdGpuArchValues.minor;
2325        if (config.amdMachineStepping == BINGEN16_DEFAULT)
2326            config.amdMachineStepping = amdGpuArchValues.stepping;
2327        if (config.kernelCodeEntryOffset == BINGEN64_DEFAULT)
2328            config.kernelCodeEntryOffset = 256;
2329        if (config.kernelCodePrefetchOffset == BINGEN64_DEFAULT)
2330            config.kernelCodePrefetchOffset = 0;
2331        if (config.kernelCodePrefetchSize == BINGEN64_DEFAULT)
2332            config.kernelCodePrefetchSize = 0;
2333        if (config.maxScrachBackingMemorySize == BINGEN64_DEFAULT) // ??
2334            config.maxScrachBackingMemorySize = 0;
2335       
2336        if (config.workitemPrivateSegmentSize == BINGEN_DEFAULT) // scratch buffer
2337            config.workitemPrivateSegmentSize =  0;
2338        if (config.workgroupGroupSegmentSize == BINGEN_DEFAULT) // local size
2339            config.workgroupGroupSegmentSize = 0;
2340        if (config.gdsSegmentSize == BINGEN_DEFAULT)
2341            config.gdsSegmentSize = 0;
2342        if (config.kernargSegmentSize == BINGEN64_DEFAULT)
2343            config.kernargSegmentSize = 0;
2344        if (config.workgroupFbarrierCount == BINGEN_DEFAULT)
2345            config.workgroupFbarrierCount = 0;
2346        if (config.reservedVgprFirst == BINGEN16_DEFAULT)
2347            config.reservedVgprFirst = 0;
2348        if (config.reservedVgprCount == BINGEN16_DEFAULT)
2349            config.reservedVgprCount = 0;
2350        if (config.reservedSgprFirst == BINGEN16_DEFAULT)
2351            config.reservedSgprFirst = 0;
2352        if (config.reservedSgprCount == BINGEN16_DEFAULT)
2353            config.reservedSgprCount = 0;
2354        if (config.debugWavefrontPrivateSegmentOffsetSgpr == BINGEN16_DEFAULT)
2355            config.debugWavefrontPrivateSegmentOffsetSgpr = 0;
2356        if (config.debugPrivateSegmentBufferSgpr == BINGEN16_DEFAULT)
2357            config.debugPrivateSegmentBufferSgpr = 0;
2358        if (config.kernargSegmentAlignment == BINGEN8_DEFAULT)
2359            config.kernargSegmentAlignment = 4; // 16 bytes
2360        if (config.groupSegmentAlignment == BINGEN8_DEFAULT)
2361            config.groupSegmentAlignment = 4; // 16 bytes
2362        if (config.privateSegmentAlignment == BINGEN8_DEFAULT)
2363            config.privateSegmentAlignment = 4; // 16 bytes
2364        if (config.wavefrontSize == BINGEN8_DEFAULT)
2365            config.wavefrontSize = 6; // 64 threads
2366       
2367        cxuint userSGPRsNum = 0;
2368        if (config.userDataNum == BINGEN8_DEFAULT)
2369        {
2370            // calcuate userSGPRs
2371            const uint16_t sgprFlags = config.enableSgprRegisterFlags;
2372            userSGPRsNum =
2373                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER)!=0 ? 4 : 0) +
2374                ((sgprFlags&ROCMFLAG_USE_DISPATCH_PTR)!=0 ? 2 : 0) +
2375                ((sgprFlags&ROCMFLAG_USE_QUEUE_PTR)!=0 ? 2 : 0) +
2376                ((sgprFlags&ROCMFLAG_USE_KERNARG_SEGMENT_PTR)!=0 ? 2 : 0) +
2377                ((sgprFlags&ROCMFLAG_USE_DISPATCH_ID)!=0 ? 2 : 0) +
2378                ((sgprFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0 ? 2 : 0) +
2379                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE)!=0) +
2380                /* use_grid_workgroup_count */
2381                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_X)!=0) +
2382                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Y)!=0) +
2383                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Z)!=0);
2384           userSGPRsNum = std::min(16U, userSGPRsNum);
2385        }
2386        else // default
2387            userSGPRsNum = config.userDataNum;
2388       
2389        /* include userData sgprs */
2390        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
2391                ((config.computePgmRsrc2>>7)&7);
2392        // extra sgprs for dimensions
2393        cxuint minRegsNum[2];
2394        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
2395                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
2396                   ((config.workitemPrivateSegmentSize!=0) ?
2397                           GPUSETUP_SCRATCH_EN : 0), minRegsNum);
2398       
2399        if (config.usedSGPRsNum!=BINGEN_DEFAULT && maxSGPRsNum < config.usedSGPRsNum)
2400        {
2401            // check only if sgprsnum set explicitly
2402            char numBuf[64];
2403            snprintf(numBuf, 64, "(max %u)", maxSGPRsNum);
2404            assembler.printError(assembler.kernels[i].sourcePos, (std::string(
2405                    "Number of total SGPRs for kernel '")+
2406                    kernelName.c_str()+"' is too high "+numBuf).c_str());
2407            good = false;
2408        }
2409        // set usedSGPRsNum
2410        if (config.usedSGPRsNum==BINGEN_DEFAULT)
2411        {
2412            cxuint flags = kernelStates[i]->allocRegFlags |
2413                // flat_scratch_init
2414                ((config.enableSgprRegisterFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0?
2415                            GCN_FLAT : 0) |
2416                // enable_xnack
2417                ((config.enableFeatureFlags&ROCMFLAG_USE_XNACK_ENABLED)!=0 ?
2418                            GCN_XNACK : 0);
2419            config.usedSGPRsNum = std::min(
2420                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]) +
2421                    getGPUExtraRegsNum(arch, REGTYPE_SGPR, flags|GCN_VCC),
2422                    maxSGPRsNum); // include all extra sgprs
2423        }
2424        // set usedVGPRsNum
2425        if (config.usedVGPRsNum==BINGEN_DEFAULT)
2426            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
2427       
2428        cxuint sgprsNum = std::max(config.usedSGPRsNum, 1U);
2429        cxuint vgprsNum = std::max(config.usedVGPRsNum, 1U);
2430        // computePGMRSRC1
2431        config.computePgmRsrc1 |= calculatePgmRSrc1(arch, vgprsNum, sgprsNum,
2432                        config.priority, config.floatMode, config.privilegedMode,
2433                        config.dx10Clamp, config.debugMode, config.ieeeMode);
2434        // computePGMRSRC2
2435        config.computePgmRsrc2 = (config.computePgmRsrc2 & 0xffffe440U) |
2436                calculatePgmRSrc2(arch, (config.workitemPrivateSegmentSize != 0),
2437                            userSGPRsNum, false, config.dimMask,
2438                            (config.computePgmRsrc2 & 0x1b80U), config.tgSize,
2439                            config.workgroupGroupSegmentSize, config.exceptions);
2440       
2441        if (config.wavefrontSgprCount == BINGEN16_DEFAULT)
2442            config.wavefrontSgprCount = sgprsNum;
2443        if (config.workitemVgprCount == BINGEN16_DEFAULT)
2444            config.workitemVgprCount = vgprsNum;
2445       
2446        if (config.callConvention == BINGEN_DEFAULT)
2447            config.callConvention = 0;
2448        if (config.runtimeLoaderKernelSymbol == BINGEN64_DEFAULT)
2449            config.runtimeLoaderKernelSymbol = 0;
2450       
2451        config.toLE(); // to little-endian
2452        // put control directive section to config
2453        if (kernel.ctrlDirSection!=ASMSECT_NONE &&
2454            assembler.sections[kernel.ctrlDirSection].content.size()==128)
2455            ::memcpy(config.controlDirective, 
2456                 assembler.sections[kernel.ctrlDirSection].content.data(), 128);
2457    }
2458   
2459    // if set adds symbols to binary
2460    std::vector<ROCmSymbolInput> dataSymbols;
2461    if (assembler.getFlags() & ASM_FORCE_ADD_SYMBOLS)
2462        for (const AsmSymbolEntry& symEntry: assembler.globalScope.symbolMap)
2463        {
2464            if (!symEntry.second.hasValue)
2465                continue; // unresolved
2466            if (ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
2467                continue; // local
2468            if (assembler.kernelMap.find(symEntry.first.c_str())!=assembler.kernelMap.end())
2469                continue; // if kernel name
2470           
2471            if (symEntry.second.sectionId==codeSection)
2472            {
2473                // put data objects
2474                dataSymbols.push_back({symEntry.first, size_t(symEntry.second.value),
2475                    size_t(symEntry.second.size), ROCmRegionType::DATA});
2476                continue;
2477            }
2478           
2479            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
2480                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
2481            if (binSectId==ELFSECTID_UNDEF)
2482                continue; // no section
2483           
2484            output.extraSymbols.push_back({ symEntry.first, symEntry.second.value,
2485                    symEntry.second.size, binSectId, false, symEntry.second.info,
2486                    symEntry.second.other });
2487        }
2488   
2489    AsmSection& asmCSection = assembler.sections[codeSection];
2490    const AsmSymbolMap& symbolMap = assembler.getSymbolMap();
2491    for (size_t ki = 0; ki < output.symbols.size(); ki++)
2492    {
2493        ROCmSymbolInput& kinput = output.symbols[ki];
2494        auto it = symbolMap.find(kinput.symbolName);
2495        if (it == symbolMap.end() || !it->second.isDefined())
2496        {
2497            // error, undefined
2498            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2499                        "Symbol for kernel '")+kinput.symbolName.c_str()+
2500                        "' is undefined").c_str());
2501            good = false;
2502            continue;
2503        }
2504        const AsmSymbol& symbol = it->second;
2505        if (!symbol.hasValue)
2506        {
2507            // error, unresolved
2508            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2509                    "Symbol for kernel '") + kinput.symbolName.c_str() +
2510                    "' is not resolved").c_str());
2511            good = false;
2512            continue;
2513        }
2514        if (symbol.sectionId != codeSection)
2515        {
2516            /// error, wrong section
2517            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2518                    "Symbol for kernel '")+kinput.symbolName.c_str()+
2519                    "' is defined for section other than '.text'").c_str());
2520            good = false;
2521            continue;
2522        }
2523        const Kernel& kernel = *kernelStates[ki];
2524        kinput.offset = symbol.value;
2525       
2526        if (asmCSection.content.size() < symbol.value + sizeof(ROCmKernelConfig))
2527        {
2528            // if kernel configuration out of section size
2529            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2530                "Code for kernel '")+kinput.symbolName.c_str()+
2531                "' is too small for configuration").c_str());
2532            good = false;
2533            continue;
2534        }
2535        else if (kernel.config!=nullptr)
2536            // put config to code section
2537            ::memcpy(asmCSection.content.data() + symbol.value,
2538                     kernel.config.get(), sizeof(ROCmKernelConfig));
2539        // set symbol type
2540        kinput.type = kernel.isFKernel ? ROCmRegionType::FKERNEL : ROCmRegionType::KERNEL;
2541    }
2542   
2543    // put data objects
2544    dataSymbols.insert(dataSymbols.end(), output.symbols.begin(), output.symbols.end());
2545    output.symbols = std::move(dataSymbols);
2546    return good;
2547}
2548
2549void AsmROCmHandler::writeBinary(std::ostream& os) const
2550{
2551    ROCmBinGenerator binGenerator(&output);
2552    binGenerator.generate(os);
2553}
2554
2555void AsmROCmHandler::writeBinary(Array<cxbyte>& array) const
2556{
2557    ROCmBinGenerator binGenerator(&output);
2558    binGenerator.generate(array);
2559}
Note: See TracBrowser for help on using the repository browser.