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

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

CLRadeonExtender: Asm: Correct default values for CWS (reqd_work_group_size) and other work group size parameters.

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