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

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

CLRadeonExtender: ROCm: change syntax of the pseudo-op '.md_symname'. initialize version of metadata to 1.0. fixed parsing of the '.arg' pseudo-op.
fixed string escaping in ROCm metadata. Escape ':' printf format in ROCm metadata. Use default symname if not supplied.

File size: 98.9 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cstdio>
22#include <cstring>
23#include <string>
24#include <vector>
25#include <unordered_set>
26#include <utility>
27#include <algorithm>
28#include <CLRX/utils/Utilities.h>
29#include <CLRX/amdasm/Assembler.h>
30#include <CLRX/amdasm/AsmFormats.h>
31#include "AsmAmdInternals.h"
32#include "AsmROCmInternals.h"
33
34using namespace CLRX;
35
36// all ROCm pseudo-op names (sorted)
37static const char* rocmPseudoOpNamesTbl[] =
38{
39    "arch_minor", "arch_stepping", "arg",
40    "call_convention", "codeversion", "config",
41    "control_directive", "cws", "debug_private_segment_buffer_sgpr",
42    "debug_wavefront_private_segment_offset_sgpr",
43    "debugmode", "default_hsa_features", "dims", "dx10clamp",
44    "eflags", "exceptions", "fixed_work_group_size",
45    "fkernel", "floatmode", "gds_segment_size",
46    "globaldata", "group_segment_align", "ieeemode", "kcode",
47    "kcodeend", "kernarg_segment_align",
48    "kernarg_segment_size", "kernel_code_entry_offset",
49    "kernel_code_prefetch_offset", "kernel_code_prefetch_size",
50    "localsize", "machine",
51    "max_flat_work_group_size", "max_scratch_backing_memory",
52    "md_group_segment_fixed_size", "md_kernarg_segment_align",
53    "md_kernarg_segment_size", "md_language","md_private_segment_fixed_size",
54    "md_sgprsnum", "md_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] = { 0, 0, 0 };
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] = { 0, 0, 0 };
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] = { 0, 0, 0 };
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    { "dynshptr", cxuint(ROCmValueKind::DYN_SHARED_PTR) },
802    { "defqueue", cxuint(ROCmValueKind::HIDDEN_DEFAULT_QUEUE) },
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_inly", 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        good &= getNameArg(asmr, 20, name, linePtr, "argument flag", true);
1014       
1015        if (::strcmp(name, "const")==0)
1016            argIsConst = true;
1017        else if (::strcmp(name, "restrict")==0)
1018            argIsRestrict= true;
1019        else if (::strcmp(name, "volatile")==0)
1020            argIsVolatile = true;
1021        else if (::strcmp(name, "pip")==0)
1022            argIsPipe = true;
1023        else
1024            ASM_NOTGOOD_BY_ERROR(fieldPlace, "Unknown argument flag")
1025    }
1026   
1027    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1028        return;
1029   
1030    handler.output.useMetadataInfo = true;
1031    ROCmKernelMetadata& metadata = handler.output.metadataInfo.kernels[asmr.currentKernel];
1032    // setup kernel arg info
1033    ROCmKernelArgInfo argInfo{};
1034    argInfo.name = argName;
1035    argInfo.typeName = typeName;
1036    argInfo.size = argSize;
1037    argInfo.align = argAlign;
1038    argInfo.pointeeAlign = pointeeAlign;
1039    argInfo.valueKind = ROCmValueKind(valueKindVal);
1040    argInfo.valueType = ROCmValueType(valueTypeVal);
1041    argInfo.addressSpace = ROCmAddressSpace(addressSpaceVal);
1042    argInfo.accessQual = ROCmAccessQual(accessQualVal);
1043    argInfo.actualAccessQual = ROCmAccessQual(actualAccessQualVal);
1044    argInfo.isConst = argIsConst;
1045    argInfo.isRestrict = argIsRestrict;
1046    argInfo.isVolatile = argIsVolatile;
1047    argInfo.isPipe = argIsPipe;
1048    // just add to kernel arguments
1049    metadata.argInfos.push_back(argInfo);
1050}
1051
1052bool AsmROCmPseudoOps::checkConfigValue(Assembler& asmr, const char* valuePlace,
1053                ROCmConfigValueTarget target, uint64_t value)
1054{
1055    bool good = true;
1056    switch(target)
1057    {
1058        case ROCMCVAL_SGPRSNUM:
1059        {
1060            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1061                        asmr.deviceType);
1062            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1063            if (value > maxSGPRsNum)
1064            {
1065                char buf[64];
1066                snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
1067                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1068            }
1069            break;
1070        }
1071        case ROCMCVAL_VGPRSNUM:
1072        {
1073            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1074                        asmr.deviceType);
1075            cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
1076            if (value > maxVGPRsNum)
1077            {
1078                char buf[64];
1079                snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
1080                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1081            }
1082            break;
1083        }
1084        case ROCMCVAL_EXCEPTIONS:
1085            asmr.printWarningForRange(7, value,
1086                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1087            value &= 0x7f;
1088            break;
1089        case ROCMCVAL_FLOATMODE:
1090            asmr.printWarningForRange(8, value,
1091                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1092            value &= 0xff;
1093            break;
1094        case ROCMCVAL_PRIORITY:
1095            asmr.printWarningForRange(2, value,
1096                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1097            value &= 3;
1098            break;
1099        case ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE: // local size
1100        {
1101            asmr.printWarningForRange(32, value,
1102                        asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1103           
1104            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1105                        asmr.deviceType);
1106            const cxuint maxLocalSize = getGPUMaxLocalSize(arch);
1107            if (value > maxLocalSize)
1108            {
1109                char buf[64];
1110                snprintf(buf, 64, "LocalSize out of range (0-%u)", maxLocalSize);
1111                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1112            }
1113            break;
1114        }
1115        case ROCMCVAL_USERDATANUM:
1116            if (value > 16)
1117                ASM_NOTGOOD_BY_ERROR(valuePlace, "UserDataNum out of range (0-16)")
1118            break;
1119        case ROCMCVAL_PRIVATE_ELEM_SIZE:
1120            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1121                ASM_NOTGOOD_BY_ERROR(valuePlace,
1122                                "Private element size must be power of two")
1123            else if (value < 2 || value > 16)
1124                ASM_NOTGOOD_BY_ERROR(valuePlace, "Private element size out of range")
1125            break;
1126        case ROCMCVAL_KERNARG_SEGMENT_ALIGN:
1127        case ROCMCVAL_GROUP_SEGMENT_ALIGN:
1128        case ROCMCVAL_PRIVATE_SEGMENT_ALIGN:
1129            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1130                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment must be power of two")
1131            else if (value < 16)
1132                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment must be not smaller than 16")
1133            break;
1134        case ROCMCVAL_WAVEFRONT_SIZE:
1135            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1136                ASM_NOTGOOD_BY_ERROR(valuePlace, "Wavefront size must be power of two")
1137            else if (value > 256)
1138                ASM_NOTGOOD_BY_ERROR(valuePlace,
1139                            "Wavefront size must be not greater than 256")
1140            break;
1141        case ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE:
1142        case ROCMCVAL_GDS_SEGMENT_SIZE:
1143        case ROCMCVAL_WORKGROUP_FBARRIER_COUNT:
1144        case ROCMCVAL_CALL_CONVENTION:
1145        case ROCMCVAL_PGMRSRC1:
1146        case ROCMCVAL_PGMRSRC2:
1147            asmr.printWarningForRange(32, value,
1148                                asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1149            break;
1150        case ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1151        case ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1152        {
1153            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1154                        asmr.deviceType);
1155            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1156            if (value >= maxSGPRsNum)
1157                ASM_NOTGOOD_BY_ERROR(valuePlace, "SGPR register out of range")
1158            break;
1159        }
1160        default:
1161            break;
1162    }
1163    return good;
1164}
1165
1166// check metadata config values
1167bool AsmROCmPseudoOps::checkMDConfigValue(Assembler& asmr, const char* valuePlace,
1168                ROCmConfigValueTarget target, uint64_t value)
1169{
1170    bool good = true;
1171    switch(target)
1172    {
1173        case ROCMCVAL_MD_WAVEFRONT_SIZE:
1174            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1175                ASM_NOTGOOD_BY_ERROR(valuePlace, "Wavefront size must be power of two")
1176            else if (value > 256)
1177                ASM_NOTGOOD_BY_ERROR(valuePlace,
1178                            "Wavefront size must be not greater than 256")
1179            break;
1180        case ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN:
1181            if (value==0 || 1ULL<<(63-CLZ64(value)) != value)
1182                ASM_NOTGOOD_BY_ERROR(valuePlace, "Alignment size must be power of two")
1183            break;
1184        case ROCMCVAL_MD_SGPRSNUM:
1185        {
1186            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1187                        asmr.deviceType);
1188            cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1189            if (value > maxSGPRsNum)
1190            {
1191                char buf[64];
1192                snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
1193                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1194            }
1195            break;
1196        }
1197        case ROCMCVAL_MD_VGPRSNUM:
1198        {
1199            const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
1200                        asmr.deviceType);
1201            cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
1202            if (value > maxVGPRsNum)
1203            {
1204                char buf[64];
1205                snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
1206                ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1207            }
1208            break;
1209        }
1210        default:
1211            break;
1212    }
1213    return good;
1214}
1215
1216void AsmROCmPseudoOps::setConfigValueMain(AsmAmdHsaKernelConfig& config,
1217                ROCmConfigValueTarget target, uint64_t value)
1218{
1219    switch(target)
1220    {
1221        case ROCMCVAL_SGPRSNUM:
1222            config.usedSGPRsNum = value;
1223            break;
1224        case ROCMCVAL_VGPRSNUM:
1225            config.usedVGPRsNum = value;
1226            break;
1227        case ROCMCVAL_PGMRSRC1:
1228            config.computePgmRsrc1 = value;
1229            break;
1230        case ROCMCVAL_PGMRSRC2:
1231            config.computePgmRsrc2 = value;
1232            break;
1233        case ROCMCVAL_FLOATMODE:
1234            config.floatMode = value;
1235            break;
1236        case ROCMCVAL_PRIORITY:
1237            config.priority = value;
1238            break;
1239        case ROCMCVAL_USERDATANUM:
1240            config.userDataNum = value;
1241            break;
1242        case ROCMCVAL_EXCEPTIONS:
1243            config.exceptions = value;
1244            break;
1245        case ROCMCVAL_KERNEL_CODE_ENTRY_OFFSET:
1246            config.kernelCodeEntryOffset = value;
1247            break;
1248        case ROCMCVAL_KERNEL_CODE_PREFETCH_OFFSET:
1249            config.kernelCodePrefetchOffset = value;
1250            break;
1251        case ROCMCVAL_KERNEL_CODE_PREFETCH_SIZE:
1252            config.kernelCodePrefetchSize = value;
1253            break;
1254        case ROCMCVAL_MAX_SCRATCH_BACKING_MEMORY:
1255            config.maxScrachBackingMemorySize = value;
1256            break;
1257        case ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE:
1258            config.workitemPrivateSegmentSize = value;
1259            break;
1260        case ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE:
1261            config.workgroupGroupSegmentSize = value;
1262            break;
1263        case ROCMCVAL_GDS_SEGMENT_SIZE:
1264            config.gdsSegmentSize = value;
1265            break;
1266        case ROCMCVAL_KERNARG_SEGMENT_SIZE:
1267            config.kernargSegmentSize = value;
1268            break;
1269        case ROCMCVAL_WORKGROUP_FBARRIER_COUNT:
1270            config.workgroupFbarrierCount = value;
1271            break;
1272        case ROCMCVAL_WAVEFRONT_SGPR_COUNT:
1273            config.wavefrontSgprCount = value;
1274            break;
1275        case ROCMCVAL_WORKITEM_VGPR_COUNT:
1276            config.workitemVgprCount = value;
1277            break;
1278        case ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1279            config.debugWavefrontPrivateSegmentOffsetSgpr = value;
1280            break;
1281        case ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1282            config.debugPrivateSegmentBufferSgpr = value;
1283            break;
1284        case ROCMCVAL_PRIVATE_ELEM_SIZE:
1285            config.enableFeatureFlags = (config.enableFeatureFlags & ~6) |
1286                    ((63-CLZ64(value)-1)<<1);
1287            break;
1288        case ROCMCVAL_KERNARG_SEGMENT_ALIGN:
1289            config.kernargSegmentAlignment = 63-CLZ64(value);
1290            break;
1291        case ROCMCVAL_GROUP_SEGMENT_ALIGN:
1292            config.groupSegmentAlignment = 63-CLZ64(value);
1293            break;
1294        case ROCMCVAL_PRIVATE_SEGMENT_ALIGN:
1295            config.privateSegmentAlignment = 63-CLZ64(value);
1296            break;
1297        case ROCMCVAL_WAVEFRONT_SIZE:
1298            config.wavefrontSize = 63-CLZ64(value);
1299            break;
1300        case ROCMCVAL_CALL_CONVENTION:
1301            config.callConvention = value;
1302            break;
1303        case ROCMCVAL_RUNTIME_LOADER_KERNEL_SYMBOL:
1304            config.runtimeLoaderKernelSymbol = value;
1305            break;
1306        default:
1307            break;
1308    }
1309}
1310
1311/// set metadata config values
1312void AsmROCmPseudoOps::setMDConfigValue(ROCmKernelMetadata& metadata,
1313                        ROCmConfigValueTarget target, uint64_t value)
1314{
1315    switch(target)
1316    {
1317        case ROCMCVAL_MD_WAVEFRONT_SIZE:
1318            metadata.wavefrontSize = value;
1319            break;
1320        case ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN:
1321            metadata.kernargSegmentAlign = value;
1322            break;
1323        case ROCMCVAL_MD_KERNARG_SEGMENT_SIZE:
1324            metadata.kernargSegmentSize = value;
1325            break;
1326        case ROCMCVAL_MD_GROUP_SEGMENT_FIXED_SIZE:
1327            metadata.groupSegmentFixedSize = value;
1328            break;
1329        case ROCMCVAL_MD_PRIVATE_SEGMENT_FIXED_SIZE:
1330            metadata.privateSegmentFixedSize = value;
1331            break;
1332        case ROCMCVAL_MD_SGPRSNUM:
1333            metadata.sgprsNum = value;
1334            break;
1335        case ROCMCVAL_MD_VGPRSNUM:
1336            metadata.vgprsNum = value;
1337            break;
1338        case ROCMCVAL_MD_SPILLEDSGPRS:
1339            metadata.spilledSgprs = value;
1340            break;
1341        case ROCMCVAL_MD_SPILLEDVGPRS:
1342            metadata.spilledVgprs = value;
1343            break;
1344        case ROCMCVAL_MAX_FLAT_WORK_GROUP_SIZE:
1345            metadata.maxFlatWorkGroupSize = value;
1346            break;
1347        default:
1348            break;
1349    }
1350}
1351
1352void AsmROCmPseudoOps::setConfigValue(AsmROCmHandler& handler, const char* pseudoOpPlace,
1353                  const char* linePtr, ROCmConfigValueTarget target)
1354{
1355    Assembler& asmr = handler.assembler;
1356    const char* end = asmr.line + asmr.lineSize;
1357   
1358    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1359        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1360        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1361   
1362    skipSpacesToEnd(linePtr, end);
1363    const char* valuePlace = linePtr;
1364    uint64_t value = BINGEN64_NOTSUPPLIED;
1365    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
1366    /* ranges checking */
1367    if (good)
1368    {
1369        if (target < ROCMCVAL_METADATA_START)
1370            good = checkConfigValue(asmr, valuePlace, target, value);
1371        else // metadata values
1372            good = checkMDConfigValue(asmr, valuePlace, target, value);
1373    }
1374    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1375        return;
1376   
1377    // set value
1378    if (target < ROCMCVAL_METADATA_START)
1379    {
1380        AsmROCmKernelConfig& config = *(handler.kernelStates[asmr.currentKernel]->config);
1381        setConfigValueMain(config, target, value);
1382    }
1383    else
1384    {
1385        // set metadata value
1386        handler.output.useMetadataInfo = true;
1387        ROCmKernelMetadata& metadata = 
1388                    handler.output.metadataInfo.kernels[asmr.currentKernel];
1389        setMDConfigValue(metadata, target, value);
1390    }
1391}
1392
1393void AsmROCmPseudoOps::setConfigBoolValueMain(AsmAmdHsaKernelConfig& config,
1394                ROCmConfigValueTarget target)
1395{
1396    switch(target)
1397    {
1398        case ROCMCVAL_PRIVMODE:
1399            config.privilegedMode = true;
1400            break;
1401        case ROCMCVAL_DEBUGMODE:
1402            config.debugMode = true;
1403            break;
1404        case ROCMCVAL_DX10CLAMP:
1405            config.dx10Clamp = true;
1406            break;
1407        case ROCMCVAL_IEEEMODE:
1408            config.ieeeMode = true;
1409            break;
1410        case ROCMCVAL_TGSIZE:
1411            config.tgSize = true;
1412            break;
1413        case ROCMCVAL_USE_PRIVATE_SEGMENT_BUFFER:
1414            config.enableSgprRegisterFlags |= ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER;
1415            break;
1416        case ROCMCVAL_USE_DISPATCH_PTR:
1417            config.enableSgprRegisterFlags |= ROCMFLAG_USE_DISPATCH_PTR;
1418            break;
1419        case ROCMCVAL_USE_QUEUE_PTR:
1420            config.enableSgprRegisterFlags |= ROCMFLAG_USE_QUEUE_PTR;
1421            break;
1422        case ROCMCVAL_USE_KERNARG_SEGMENT_PTR:
1423            config.enableSgprRegisterFlags |= ROCMFLAG_USE_KERNARG_SEGMENT_PTR;
1424            break;
1425        case ROCMCVAL_USE_DISPATCH_ID:
1426            config.enableSgprRegisterFlags |= ROCMFLAG_USE_DISPATCH_ID;
1427            break;
1428        case ROCMCVAL_USE_FLAT_SCRATCH_INIT:
1429            config.enableSgprRegisterFlags |= ROCMFLAG_USE_FLAT_SCRATCH_INIT;
1430            break;
1431        case ROCMCVAL_USE_PRIVATE_SEGMENT_SIZE:
1432            config.enableSgprRegisterFlags |= ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE;
1433            break;
1434        case ROCMCVAL_USE_ORDERED_APPEND_GDS:
1435            config.enableFeatureFlags |= ROCMFLAG_USE_ORDERED_APPEND_GDS;
1436            break;
1437        case ROCMCVAL_USE_PTR64:
1438            config.enableFeatureFlags |= ROCMFLAG_USE_PTR64;
1439            break;
1440        case ROCMCVAL_USE_DYNAMIC_CALL_STACK:
1441            config.enableFeatureFlags |= ROCMFLAG_USE_DYNAMIC_CALL_STACK;
1442            break;
1443        case ROCMCVAL_USE_DEBUG_ENABLED:
1444            config.enableFeatureFlags |= ROCMFLAG_USE_DEBUG_ENABLED;
1445            break;
1446        case ROCMCVAL_USE_XNACK_ENABLED:
1447            config.enableFeatureFlags |= ROCMFLAG_USE_XNACK_ENABLED;
1448            break;
1449        default:
1450            break;
1451    }
1452}
1453
1454void AsmROCmPseudoOps::setConfigBoolValue(AsmROCmHandler& handler,
1455          const char* pseudoOpPlace, const char* linePtr, ROCmConfigValueTarget target)
1456{
1457    Assembler& asmr = handler.assembler;
1458    const char* end = asmr.line + asmr.lineSize;
1459   
1460    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1461        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1462        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1463   
1464    skipSpacesToEnd(linePtr, end);
1465    if (!checkGarbagesAtEnd(asmr, linePtr))
1466        return;
1467   
1468    AsmROCmKernelConfig& config = *(handler.kernelStates[asmr.currentKernel]->config);
1469   
1470    setConfigBoolValueMain(config, target);
1471}
1472
1473void AsmROCmPseudoOps::setDefaultHSAFeatures(AsmROCmHandler& handler,
1474                    const char* pseudoOpPlace, const char* linePtr)
1475{
1476    Assembler& asmr = handler.assembler;
1477   
1478    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1479        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1480        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1481   
1482    if (!checkGarbagesAtEnd(asmr, linePtr))
1483        return;
1484   
1485    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1486    config->enableSgprRegisterFlags = uint16_t(ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER|
1487                    ROCMFLAG_USE_DISPATCH_PTR|ROCMFLAG_USE_KERNARG_SEGMENT_PTR);
1488    config->enableFeatureFlags = uint16_t(AMDHSAFLAG_USE_PTR64|2);
1489}
1490
1491void AsmROCmPseudoOps::setDimensions(AsmROCmHandler& handler, const char* pseudoOpPlace,
1492                  const char* linePtr)
1493{
1494    Assembler& asmr = handler.assembler;
1495    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1496        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1497        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1498    cxuint dimMask = 0;
1499    if (!parseDimensions(asmr, linePtr, dimMask))
1500        return;
1501    if (!checkGarbagesAtEnd(asmr, linePtr))
1502        return;
1503    handler.kernelStates[asmr.currentKernel]->config->dimMask = dimMask;
1504}
1505
1506// parse machine version - used also in AsmGalliumFormat
1507// four numbers - kind, major, minor, stepping
1508bool AsmROCmPseudoOps::parseMachine(Assembler& asmr, const char* linePtr,
1509        uint16_t& machineKind, uint16_t& machineMajor, uint16_t& machineMinor,
1510        uint16_t& machineStepping)
1511{
1512    const char* end = asmr.line + asmr.lineSize;
1513   
1514    skipSpacesToEnd(linePtr, end);
1515    uint64_t kindValue = 0;
1516    uint64_t majorValue = 0;
1517    uint64_t minorValue = 0;
1518    uint64_t steppingValue = 0;
1519    const char* valuePlace = linePtr;
1520    bool good = getAbsoluteValueArg(asmr, kindValue, linePtr, true);
1521    // parse kind
1522    asmr.printWarningForRange(16, kindValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1523    if (!skipRequiredComma(asmr, linePtr))
1524        return false;
1525   
1526    valuePlace = linePtr;
1527    good &= getAbsoluteValueArg(asmr, majorValue, linePtr, true);
1528    // parse major
1529    asmr.printWarningForRange(16, majorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1530    if (!skipRequiredComma(asmr, linePtr))
1531        return false;
1532   
1533    valuePlace = linePtr;
1534    good &= getAbsoluteValueArg(asmr, minorValue, linePtr, true);
1535    // parse minor
1536    asmr.printWarningForRange(16, minorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1537    if (!skipRequiredComma(asmr, linePtr))
1538        return false;
1539   
1540    valuePlace = linePtr;
1541    // parse stepping
1542    good &= getAbsoluteValueArg(asmr, steppingValue, linePtr, true);
1543    asmr.printWarningForRange(16, steppingValue,
1544                      asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1545   
1546    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1547        return false;
1548   
1549    machineKind = kindValue;
1550    machineMajor = majorValue;
1551    machineMinor = minorValue;
1552    machineStepping = steppingValue;
1553    return true;
1554}
1555
1556// set machine - four numbers - kind, major, minor, stepping
1557void AsmROCmPseudoOps::setMachine(AsmROCmHandler& handler, const char* pseudoOpPlace,
1558                      const char* linePtr)
1559{
1560    Assembler& asmr = handler.assembler;
1561    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1562        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1563        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1564   
1565    uint16_t kindValue = 0, majorValue = 0;
1566    uint16_t minorValue = 0, steppingValue = 0;
1567    if (!parseMachine(asmr, linePtr, kindValue, majorValue, minorValue, steppingValue))
1568        return;
1569   
1570    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1571    config->amdMachineKind = kindValue;
1572    config->amdMachineMajor = majorValue;
1573    config->amdMachineMinor = minorValue;
1574    config->amdMachineStepping = steppingValue;
1575}
1576
1577// parse code version (amd code version) - used also in AsmGalliumFormat
1578// two numbers - major and minor
1579bool AsmROCmPseudoOps::parseCodeVersion(Assembler& asmr, const char* linePtr,
1580                uint16_t& codeMajor, uint16_t& codeMinor)
1581{
1582    const char* end = asmr.line + asmr.lineSize;
1583   
1584    skipSpacesToEnd(linePtr, end);
1585    uint64_t majorValue = 0;
1586    uint64_t minorValue = 0;
1587    const char* valuePlace = linePtr;
1588    // parse version major
1589    bool good = getAbsoluteValueArg(asmr, majorValue, linePtr, true);
1590    asmr.printWarningForRange(32, majorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1591    if (!skipRequiredComma(asmr, linePtr))
1592        return false;
1593   
1594    valuePlace = linePtr;
1595    // parse version minor
1596    good &= getAbsoluteValueArg(asmr, minorValue, linePtr, true);
1597    asmr.printWarningForRange(32, minorValue, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
1598   
1599    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1600        return false;
1601   
1602    codeMajor = majorValue;
1603    codeMinor = minorValue;
1604    return true;
1605}
1606
1607// two numbers - major and minor
1608void AsmROCmPseudoOps::setCodeVersion(AsmROCmHandler& handler, const char* pseudoOpPlace,
1609                  const char* linePtr)
1610{
1611    Assembler& asmr = handler.assembler;
1612    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1613        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1614        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1615   
1616    uint16_t majorValue = 0, minorValue = 0;
1617    if (!parseCodeVersion(asmr, linePtr, majorValue, minorValue))
1618        return;
1619   
1620    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1621    config->amdCodeVersionMajor = majorValue;
1622    config->amdCodeVersionMinor = minorValue;
1623}
1624
1625// parse reserved gprs - used also in AsmGalliumFormat
1626// parsereserved S/VGRPS - first number is first register, second is last register
1627bool AsmROCmPseudoOps::parseReservedXgprs(Assembler& asmr, const char* linePtr,
1628                bool inVgpr, uint16_t& gprFirst, uint16_t& gprCount)
1629{
1630    const char* end = asmr.line + asmr.lineSize;
1631    skipSpacesToEnd(linePtr, end);
1632    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(asmr.deviceType);
1633    cxuint maxGPRsNum = getGPUMaxRegistersNum(arch,
1634                       inVgpr ? REGTYPE_VGPR : REGTYPE_SGPR, 0);
1635   
1636    uint64_t firstReg = BINGEN_NOTSUPPLIED;
1637    uint64_t lastReg = BINGEN_NOTSUPPLIED;
1638    const char* valuePlace = linePtr;
1639    bool haveFirstReg;
1640    bool good = getAbsoluteValueArg(asmr, firstReg, linePtr, true);
1641    haveFirstReg = good;
1642    if (haveFirstReg && firstReg > maxGPRsNum-1)
1643    {
1644        // first register is out of range
1645        char buf[64];
1646        snprintf(buf, 64, "First reserved %s register out of range (0-%u)",
1647                 inVgpr ? "VGPR" : "SGPR",  maxGPRsNum-1);
1648        ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1649    }
1650    if (!skipRequiredComma(asmr, linePtr))
1651        return false;
1652   
1653    valuePlace = linePtr;
1654    bool haveLastReg = getAbsoluteValueArg(asmr, lastReg, linePtr, true);
1655    good &= haveLastReg;
1656    if (haveLastReg && lastReg > maxGPRsNum-1)
1657    {
1658        // if last register out of range
1659        char buf[64];
1660        snprintf(buf, 64, "Last reserved %s register out of range (0-%u)",
1661                 inVgpr ? "VGPR" : "SGPR", maxGPRsNum-1);
1662        ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
1663    }
1664    if (haveFirstReg && haveLastReg && firstReg > lastReg)
1665        ASM_NOTGOOD_BY_ERROR(valuePlace, "Wrong register range")
1666   
1667    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1668        return false;
1669   
1670    gprFirst = firstReg;
1671    gprCount = lastReg-firstReg+1;
1672    return true;
1673}
1674
1675/// set reserved S/VGRPS - first number is first register, second is last register
1676void AsmROCmPseudoOps::setReservedXgprs(AsmROCmHandler& handler, const char* pseudoOpPlace,
1677                      const char* linePtr, bool inVgpr)
1678{
1679    Assembler& asmr = handler.assembler;
1680    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1681        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1682        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1683   
1684    uint16_t gprFirst = 0, gprCount = 0;
1685    if (!parseReservedXgprs(asmr, linePtr, inVgpr, gprFirst, gprCount))
1686        return;
1687   
1688    AsmROCmKernelConfig* config = handler.kernelStates[asmr.currentKernel]->config.get();
1689    if (inVgpr)
1690    {
1691        config->reservedVgprFirst = gprFirst;
1692        config->reservedVgprCount = gprCount;
1693    }
1694    else
1695    {
1696        config->reservedSgprFirst = gprFirst;
1697        config->reservedSgprCount = gprCount;
1698    }
1699}
1700
1701// set UseGridWorkGroupCount - 3 bits for dimensions
1702void AsmROCmPseudoOps::setUseGridWorkGroupCount(AsmROCmHandler& handler,
1703                   const char* pseudoOpPlace, const char* linePtr)
1704{
1705    Assembler& asmr = handler.assembler;
1706    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1707        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1708        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1709    cxuint dimMask = 0;
1710    if (!parseDimensions(asmr, linePtr, dimMask))
1711        return;
1712    if (!checkGarbagesAtEnd(asmr, linePtr))
1713        return;
1714    uint16_t& flags = handler.kernelStates[asmr.currentKernel]->config->
1715                enableSgprRegisterFlags;
1716    flags = (flags & ~(7<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT)) |
1717            (dimMask<<ROCMFLAG_USE_GRID_WORKGROUP_COUNT_BIT);
1718}
1719
1720void AsmROCmPseudoOps::updateKCodeSel(AsmROCmHandler& handler,
1721                  const std::vector<cxuint>& oldset)
1722{
1723    Assembler& asmr = handler.assembler;
1724    // old elements - join current regstate with all them
1725    size_t regTypesNum;
1726    for (auto it = oldset.begin(); it != oldset.end(); ++it)
1727    {
1728        Flags curAllocRegFlags;
1729        const cxuint* curAllocRegs = asmr.isaAssembler->getAllocatedRegisters(regTypesNum,
1730                               curAllocRegFlags);
1731        cxuint newAllocRegs[MAX_REGTYPES_NUM];
1732        AsmROCmHandler::Kernel& kernel = *(handler.kernelStates[*it]);
1733        for (size_t i = 0; i < regTypesNum; i++)
1734            newAllocRegs[i] = std::max(curAllocRegs[i], kernel.allocRegs[i]);
1735        kernel.allocRegFlags |= curAllocRegFlags;
1736        std::copy(newAllocRegs, newAllocRegs+regTypesNum, kernel.allocRegs);
1737    }
1738    asmr.isaAssembler->setAllocatedRegisters();
1739}
1740
1741void AsmROCmPseudoOps::doKCode(AsmROCmHandler& handler, const char* pseudoOpPlace,
1742                  const char* linePtr)
1743{
1744    Assembler& asmr = handler.assembler;
1745    const char* end = asmr.line + asmr.lineSize;
1746    bool good = true;
1747    skipSpacesToEnd(linePtr, end);
1748    if (linePtr==end)
1749        return;
1750    std::unordered_set<cxuint> newSel(handler.kcodeSelection.begin(),
1751                          handler.kcodeSelection.end());
1752    do {
1753        CString kname;
1754        const char* knamePlace = linePtr;
1755        skipSpacesToEnd(linePtr, end);
1756        bool removeKernel = false;
1757        if (linePtr!=end && *linePtr=='-')
1758        {
1759            // '-' - remove this kernel from current kernel selection
1760            removeKernel = true;
1761            linePtr++;
1762        }
1763        else if (linePtr!=end && *linePtr=='+')
1764        {
1765            linePtr++;
1766            skipSpacesToEnd(linePtr, end);
1767            if (linePtr==end)
1768            {
1769                // add all kernels
1770                for (cxuint k = 0; k < handler.kernelStates.size(); k++)
1771                    newSel.insert(k);
1772                break;
1773            }
1774        }
1775       
1776        if (!getNameArg(asmr, kname, linePtr, "kernel"))
1777        { good = false; continue; }
1778        auto kit = asmr.kernelMap.find(kname);
1779        if (kit == asmr.kernelMap.end())
1780        {
1781            asmr.printError(knamePlace, "Kernel not found");
1782            continue;
1783        }
1784        if (!removeKernel)
1785            newSel.insert(kit->second);
1786        else // remove kernel
1787            newSel.erase(kit->second);
1788    } while (skipCommaForMultipleArgs(asmr, linePtr));
1789   
1790    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1791        return;
1792   
1793    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
1794        PSEUDOOP_RETURN_BY_ERROR("KCode outside code")
1795    if (handler.kcodeSelStack.empty())
1796        handler.saveKcodeCurrentAllocRegs();
1797    // push to stack
1798    handler.kcodeSelStack.push(handler.kcodeSelection);
1799    // set current sel
1800    handler.kcodeSelection.assign(newSel.begin(), newSel.end());
1801    std::sort(handler.kcodeSelection.begin(), handler.kcodeSelection.end());
1802   
1803    const std::vector<cxuint>& oldKCodeSel = handler.kcodeSelStack.top();
1804    if (!oldKCodeSel.empty())
1805        asmr.handleRegionsOnKernels(handler.kcodeSelection, oldKCodeSel,
1806                            handler.codeSection);
1807    else if (handler.currentKcodeKernel != ASMKERN_GLOBAL)
1808    {
1809        std::vector<cxuint> tempKCodeSel;
1810        tempKCodeSel.push_back(handler.currentKcodeKernel);
1811        asmr.handleRegionsOnKernels(handler.kcodeSelection, tempKCodeSel,
1812                            handler.codeSection);
1813    }
1814   
1815    updateKCodeSel(handler, handler.kcodeSelStack.top());
1816}
1817
1818void AsmROCmPseudoOps::doKCodeEnd(AsmROCmHandler& handler, const char* pseudoOpPlace,
1819                  const char* linePtr)
1820{
1821    Assembler& asmr = handler.assembler;
1822    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
1823        PSEUDOOP_RETURN_BY_ERROR("KCodeEnd outside code")
1824    if (handler.kcodeSelStack.empty())
1825        PSEUDOOP_RETURN_BY_ERROR("'.kcodeend' without '.kcode'")
1826    if (!checkGarbagesAtEnd(asmr, linePtr))
1827        return;
1828   
1829    updateKCodeSel(handler, handler.kcodeSelection);
1830    std::vector<cxuint> oldKCodeSel = handler.kcodeSelection;
1831    handler.kcodeSelection = handler.kcodeSelStack.top();
1832   
1833    if (!handler.kcodeSelection.empty())
1834        asmr.handleRegionsOnKernels(handler.kcodeSelection, oldKCodeSel,
1835                        handler.codeSection);
1836    else if (handler.currentKcodeKernel != ASMKERN_GLOBAL)
1837    {
1838        // if choosen current kernel
1839        std::vector<cxuint> curKernelSel;
1840        curKernelSel.push_back(handler.currentKcodeKernel);
1841        asmr.handleRegionsOnKernels(curKernelSel, oldKCodeSel, handler.codeSection);
1842    }
1843   
1844    handler.kcodeSelStack.pop();
1845    if (handler.kcodeSelStack.empty())
1846        handler.restoreKcodeCurrentAllocRegs();
1847}
1848
1849}
1850
1851bool AsmROCmHandler::parsePseudoOp(const CString& firstName, const char* stmtPlace,
1852               const char* linePtr)
1853{
1854    const size_t pseudoOp = binaryFind(rocmPseudoOpNamesTbl, rocmPseudoOpNamesTbl +
1855                    sizeof(rocmPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
1856                   CStringLess()) - rocmPseudoOpNamesTbl;
1857   
1858    switch(pseudoOp)
1859    {
1860        case ROCMOP_ARCH_MINOR:
1861            AsmROCmPseudoOps::setArchMinor(*this, linePtr);
1862            break;
1863        case ROCMOP_ARCH_STEPPING:
1864            AsmROCmPseudoOps::setArchStepping(*this, linePtr);
1865            break;
1866        case ROCMOP_ARG:
1867            AsmROCmPseudoOps::addKernelArg(*this, stmtPlace, linePtr);
1868            break;
1869        case ROCMOP_CALL_CONVENTION:
1870            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1871                             ROCMCVAL_CALL_CONVENTION);
1872            break;
1873        case ROCMOP_CODEVERSION:
1874            AsmROCmPseudoOps::setCodeVersion(*this, stmtPlace, linePtr);
1875            break;
1876        case ROCMOP_CONFIG:
1877            AsmROCmPseudoOps::doConfig(*this, stmtPlace, linePtr);
1878            break;
1879        case ROCMOP_CONTROL_DIRECTIVE:
1880            AsmROCmPseudoOps::doControlDirective(*this, stmtPlace, linePtr);
1881            break;
1882        case ROCMOP_CWS:
1883        case ROCMOP_REQD_WORK_GROUP_SIZE:
1884            AsmROCmPseudoOps::setCWS(*this, stmtPlace, linePtr);
1885            break;
1886        case ROCMOP_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR:
1887            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1888                             ROCMCVAL_DEBUG_PRIVATE_SEGMENT_BUFFER_SGPR);
1889            break;
1890        case ROCMOP_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR:
1891            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1892                         ROCMCVAL_DEBUG_WAVEFRONT_PRIVATE_SEGMENT_OFFSET_SGPR);
1893            break;
1894        case ROCMOP_DEBUGMODE:
1895            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1896                             ROCMCVAL_DEBUGMODE);
1897            break;
1898        case ROCMOP_DIMS:
1899            AsmROCmPseudoOps::setDimensions(*this, stmtPlace, linePtr);
1900            break;
1901        case ROCMOP_DX10CLAMP:
1902            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1903                             ROCMCVAL_DX10CLAMP);
1904            break;
1905        case ROCMOP_EFLAGS:
1906            AsmROCmPseudoOps::setEFlags(*this, linePtr);
1907            break;
1908        case ROCMOP_EXCEPTIONS:
1909            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1910                             ROCMCVAL_EXCEPTIONS);
1911            break;
1912        case ROCMOP_FIXED_WORK_GROUP_SIZE:
1913            AsmROCmPseudoOps::setFixedWorkGroupSize(*this, stmtPlace, linePtr);
1914            break;
1915        case ROCMOP_FKERNEL:
1916            AsmROCmPseudoOps::doFKernel(*this, stmtPlace, linePtr);
1917            break;
1918        case ROCMOP_FLOATMODE:
1919            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1920                             ROCMCVAL_FLOATMODE);
1921            break;
1922        case ROCMOP_GLOBALDATA:
1923            AsmROCmPseudoOps::doGlobalData(*this, stmtPlace, linePtr);
1924            break;
1925        case ROCMOP_GDS_SEGMENT_SIZE:
1926            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1927                             ROCMCVAL_GDS_SEGMENT_SIZE);
1928            break;
1929        case ROCMOP_GROUP_SEGMENT_ALIGN:
1930            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1931                             ROCMCVAL_GROUP_SEGMENT_ALIGN);
1932            break;
1933        case ROCMOP_DEFAULT_HSA_FEATURES:
1934            AsmROCmPseudoOps::setDefaultHSAFeatures(*this, stmtPlace, linePtr);
1935            break;
1936        case ROCMOP_IEEEMODE:
1937            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1938                             ROCMCVAL_IEEEMODE);
1939            break;
1940        case ROCMOP_KCODE:
1941            AsmROCmPseudoOps::doKCode(*this, stmtPlace, linePtr);
1942            break;
1943        case ROCMOP_KCODEEND:
1944            AsmROCmPseudoOps::doKCodeEnd(*this, stmtPlace, linePtr);
1945            break;
1946        case ROCMOP_KERNARG_SEGMENT_ALIGN:
1947            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1948                             ROCMCVAL_KERNARG_SEGMENT_ALIGN);
1949            break;
1950        case ROCMOP_KERNARG_SEGMENT_SIZE:
1951            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1952                             ROCMCVAL_KERNARG_SEGMENT_SIZE);
1953            break;
1954        case ROCMOP_KERNEL_CODE_ENTRY_OFFSET:
1955            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1956                             ROCMCVAL_KERNEL_CODE_ENTRY_OFFSET);
1957            break;
1958        case ROCMOP_KERNEL_CODE_PREFETCH_OFFSET:
1959            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1960                             ROCMCVAL_KERNEL_CODE_PREFETCH_OFFSET);
1961            break;
1962        case ROCMOP_KERNEL_CODE_PREFETCH_SIZE:
1963            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1964                             ROCMCVAL_KERNEL_CODE_PREFETCH_SIZE);
1965            break;
1966        case ROCMOP_LOCALSIZE:
1967            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1968                             ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE);
1969            break;
1970        case ROCMOP_MACHINE:
1971            AsmROCmPseudoOps::setMachine(*this, stmtPlace, linePtr);
1972            break;
1973        case ROCMOP_MAX_FLAT_WORK_GROUP_SIZE:
1974            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1975                            ROCMCVAL_MAX_FLAT_WORK_GROUP_SIZE);
1976            break;
1977        case ROCMOP_MAX_SCRATCH_BACKING_MEMORY:
1978            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1979                             ROCMCVAL_MAX_SCRATCH_BACKING_MEMORY);
1980            break;
1981        case ROCMOP_METADATA:
1982            AsmROCmPseudoOps::addMetadata(*this, stmtPlace, linePtr);
1983            break;
1984        case ROCMOP_MD_GROUP_SEGMENT_FIXED_SIZE:
1985            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1986                            ROCMCVAL_MD_GROUP_SEGMENT_FIXED_SIZE);
1987            break;
1988        case ROCMOP_MD_KERNARG_SEGMENT_ALIGN:
1989            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1990                            ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN);
1991            break;
1992        case ROCMOP_MD_KERNARG_SEGMENT_SIZE:
1993            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1994                            ROCMCVAL_MD_KERNARG_SEGMENT_ALIGN);
1995            break;
1996        case ROCMOP_MD_LANGUAGE:
1997            AsmROCmPseudoOps::setKernelLanguage(*this, stmtPlace, linePtr);
1998            break;
1999        case ROCMOP_MD_PRIVATE_SEGMENT_FIXED_SIZE:
2000            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2001                            ROCMCVAL_MD_PRIVATE_SEGMENT_FIXED_SIZE);
2002            break;
2003        case ROCMOP_MD_SPILLEDSGPRS:
2004            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2005                            ROCMCVAL_MD_SPILLEDSGPRS);
2006            break;
2007        case ROCMOP_MD_SPILLEDVGPRS:
2008            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2009                            ROCMCVAL_MD_SPILLEDVGPRS);
2010            break;
2011        case ROCMOP_MD_SGPRSNUM:
2012            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2013                            ROCMCVAL_MD_SGPRSNUM);
2014            break;
2015        case ROCMOP_MD_SYMNAME:
2016            AsmROCmPseudoOps::setKernelSymName(*this, stmtPlace, linePtr);
2017            break;
2018        case ROCMOP_MD_VERSION:
2019            AsmROCmPseudoOps::setMetadataVersion(*this, stmtPlace, linePtr);
2020            break;
2021        case ROCMOP_MD_VGPRSNUM:
2022            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2023                            ROCMCVAL_MD_VGPRSNUM);
2024            break;
2025        case ROCMOP_MD_WAVEFRONT_SIZE:
2026            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2027                            ROCMCVAL_MD_WAVEFRONT_SIZE);
2028            break;
2029        case ROCMOP_NEWBINFMT:
2030            AsmROCmPseudoOps::setNewBinFormat(*this, linePtr);
2031            break;
2032        case ROCMOP_PGMRSRC1:
2033            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PGMRSRC1);
2034            break;
2035        case ROCMOP_PGMRSRC2:
2036            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PGMRSRC2);
2037            break;
2038        case ROCMOP_PRINTF:
2039            AsmROCmPseudoOps::addPrintf(*this, stmtPlace, linePtr);
2040            break;
2041        case ROCMOP_PRIORITY:
2042            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_PRIORITY);
2043            break;
2044        case ROCMOP_PRIVATE_ELEM_SIZE:
2045            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2046                             ROCMCVAL_PRIVATE_ELEM_SIZE);
2047            break;
2048        case ROCMOP_PRIVATE_SEGMENT_ALIGN:
2049            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2050                             ROCMCVAL_PRIVATE_SEGMENT_ALIGN);
2051            break;
2052        case ROCMOP_PRIVMODE:
2053            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2054                             ROCMCVAL_PRIVMODE);
2055            break;
2056        case ROCMOP_RESERVED_SGPRS:
2057            AsmROCmPseudoOps::setReservedXgprs(*this, stmtPlace, linePtr, false);
2058            break;
2059        case ROCMOP_RESERVED_VGPRS:
2060            AsmROCmPseudoOps::setReservedXgprs(*this, stmtPlace, linePtr, true);
2061            break;
2062        case ROCMOP_RUNTIME_HANDLE:
2063            break;
2064        case ROCMOP_RUNTIME_LOADER_KERNEL_SYMBOL:
2065            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2066                             ROCMCVAL_RUNTIME_LOADER_KERNEL_SYMBOL);
2067            break;
2068        case ROCMOP_SCRATCHBUFFER:
2069            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2070                             ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE);
2071            break;
2072        case ROCMOP_SGPRSNUM:
2073            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2074                             ROCMCVAL_SGPRSNUM);
2075            break;
2076        case ROCMOP_TARGET:
2077            AsmROCmPseudoOps::setTarget(*this, linePtr, false);
2078            break;
2079        case ROCMOP_TGSIZE:
2080            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2081                             ROCMCVAL_TGSIZE);
2082            break;
2083        case ROCMOP_TRIPPLE:
2084            AsmROCmPseudoOps::setTarget(*this, linePtr, true);
2085            break;
2086        case ROCMOP_USE_DEBUG_ENABLED:
2087            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2088                             ROCMCVAL_USE_DEBUG_ENABLED);
2089            break;
2090        case ROCMOP_USE_DISPATCH_ID:
2091            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2092                             ROCMCVAL_USE_DISPATCH_ID);
2093            break;
2094        case ROCMOP_USE_DISPATCH_PTR:
2095            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2096                             ROCMCVAL_USE_DISPATCH_PTR);
2097            break;
2098        case ROCMOP_USE_DYNAMIC_CALL_STACK:
2099            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2100                             ROCMCVAL_USE_DYNAMIC_CALL_STACK);
2101            break;
2102        case ROCMOP_USE_FLAT_SCRATCH_INIT:
2103            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2104                             ROCMCVAL_USE_FLAT_SCRATCH_INIT);
2105            break;
2106        case ROCMOP_USE_GRID_WORKGROUP_COUNT:
2107            AsmROCmPseudoOps::setUseGridWorkGroupCount(*this, stmtPlace, linePtr);
2108            break;
2109        case ROCMOP_USE_KERNARG_SEGMENT_PTR:
2110            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2111                             ROCMCVAL_USE_KERNARG_SEGMENT_PTR);
2112            break;
2113        case ROCMOP_USE_ORDERED_APPEND_GDS:
2114            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2115                             ROCMCVAL_USE_ORDERED_APPEND_GDS);
2116            break;
2117        case ROCMOP_USE_PRIVATE_SEGMENT_SIZE:
2118            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2119                             ROCMCVAL_USE_PRIVATE_SEGMENT_SIZE);
2120            break;
2121        case ROCMOP_USE_PTR64:
2122            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2123                             ROCMCVAL_USE_PTR64);
2124            break;
2125        case ROCMOP_USE_QUEUE_PTR:
2126            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2127                             ROCMCVAL_USE_QUEUE_PTR);
2128            break;
2129        case ROCMOP_USE_PRIVATE_SEGMENT_BUFFER:
2130            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2131                             ROCMCVAL_USE_PRIVATE_SEGMENT_BUFFER);
2132            break;
2133        case ROCMOP_USE_XNACK_ENABLED:
2134            AsmROCmPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
2135                             ROCMCVAL_USE_XNACK_ENABLED);
2136            break;
2137        case ROCMOP_USERDATANUM:
2138            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2139                             ROCMCVAL_USERDATANUM);
2140            break;
2141        case ROCMOP_VECTYPEHINT:
2142            AsmROCmPseudoOps::setVecTypeHint(*this, stmtPlace, linePtr);
2143            break;
2144        case ROCMOP_VGPRSNUM:
2145            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr, ROCMCVAL_VGPRSNUM);
2146            break;
2147        case ROCMOP_WAVEFRONT_SGPR_COUNT:
2148            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2149                             ROCMCVAL_WAVEFRONT_SGPR_COUNT);
2150            break;
2151        case ROCMOP_WAVEFRONT_SIZE:
2152            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2153                             ROCMCVAL_WAVEFRONT_SIZE);
2154            break;
2155        case ROCMOP_WORKITEM_VGPR_COUNT:
2156            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2157                             ROCMCVAL_WORKITEM_VGPR_COUNT);
2158            break;
2159        case ROCM_WORK_GROUP_SIZE_HINT:
2160            AsmROCmPseudoOps::setWorkGroupSizeHint(*this, stmtPlace, linePtr);
2161            break;
2162        case ROCMOP_WORKGROUP_FBARRIER_COUNT:
2163            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2164                             ROCMCVAL_WORKGROUP_FBARRIER_COUNT);
2165            break;
2166        case ROCMOP_WORKGROUP_GROUP_SEGMENT_SIZE:
2167            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2168                             ROCMCVAL_WORKGROUP_GROUP_SEGMENT_SIZE);
2169            break;
2170        case ROCMOP_WORKITEM_PRIVATE_SEGMENT_SIZE:
2171            AsmROCmPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
2172                             ROCMCVAL_WORKITEM_PRIVATE_SEGMENT_SIZE);
2173            break;
2174        default:
2175            return false;
2176    }
2177    return true;
2178}
2179
2180bool AsmROCmHandler::prepareBinary()
2181{
2182    bool good = true;
2183    size_t sectionsNum = sections.size();
2184    output.deviceType = assembler.getDeviceType();
2185   
2186    if (assembler.isaAssembler!=nullptr)
2187    {
2188        // make last kernel registers pool updates
2189        if (kcodeSelStack.empty())
2190            saveKcodeCurrentAllocRegs();
2191        else
2192            while (!kcodeSelStack.empty())
2193            {
2194                // pop from kcode stack and apply changes
2195                AsmROCmPseudoOps::updateKCodeSel(*this, kcodeSelection);
2196                kcodeSelection = kcodeSelStack.top();
2197                kcodeSelStack.pop();
2198            }
2199    }
2200   
2201    // set sections as outputs
2202    for (size_t i = 0; i < sectionsNum; i++)
2203    {
2204        const AsmSection& asmSection = assembler.sections[i];
2205        const Section& section = sections[i];
2206        const size_t sectionSize = asmSection.getSize();
2207        const cxbyte* sectionData = (!asmSection.content.empty()) ?
2208                asmSection.content.data() : (const cxbyte*)"";
2209        switch(asmSection.type)
2210        {
2211            case AsmSectionType::CODE:
2212                output.codeSize = sectionSize;
2213                output.code = sectionData;
2214                break;
2215            case AsmSectionType::EXTRA_PROGBITS:
2216            case AsmSectionType::EXTRA_NOTE:
2217            case AsmSectionType::EXTRA_NOBITS:
2218            case AsmSectionType::EXTRA_SECTION:
2219            {
2220                // handle extra (user) section, set section type and its flags
2221                uint32_t elfSectType =
2222                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
2223                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
2224                             SHT_PROGBITS;
2225                uint32_t elfSectFlags = 
2226                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
2227                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
2228                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
2229                output.extraSections.push_back({section.name, sectionSize, sectionData,
2230                    asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
2231                    elfSectFlags, ELFSECTID_NULL, 0, 0 });
2232                break;
2233            }
2234            case AsmSectionType::ROCM_CONFIG_CTRL_DIRECTIVE:
2235                if (sectionSize != 128)
2236                    // control directive accepts only 128-byte size
2237                    assembler.printError(AsmSourcePos(),
2238                         (std::string("Section '.control_directive' for kernel '")+
2239                          assembler.kernels[section.kernelId].name+
2240                          "' have wrong size").c_str());
2241                break;
2242            case AsmSectionType::ROCM_COMMENT:
2243                output.commentSize = sectionSize;
2244                output.comment = (const char*)sectionData;
2245                break;
2246            case AsmSectionType::DATA:
2247                output.globalDataSize = sectionSize;
2248                output.globalData = sectionData;
2249                break;
2250            case AsmSectionType::ROCM_METADATA:
2251                output.metadataSize = sectionSize;
2252                output.metadata = (const char*)sectionData;
2253                break;
2254            default:
2255                break;
2256        }
2257    }
2258   
2259    // enable metadata config for new binary format by default (if no metadata section)
2260    if (output.newBinFormat && output.metadata==nullptr)
2261        output.useMetadataInfo = true;
2262   
2263    GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
2264    // set up number of the allocated SGPRs and VGPRs for kernel
2265    cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
2266   
2267    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(assembler.deviceType,
2268                                GPUArchVersionTable::OPENSOURCE);
2269    // replace arch minor and stepping by user defined values (if set)
2270    if (output.archMinor!=UINT32_MAX)
2271        amdGpuArchValues.minor = output.archMinor;
2272    if (output.archStepping!=UINT32_MAX)
2273        amdGpuArchValues.stepping = output.archStepping;
2274   
2275    // prepare kernels configuration
2276    for (size_t i = 0; i < kernelStates.size(); i++)
2277    {
2278        const Kernel& kernel = *kernelStates[i];
2279        if (kernel.config.get() == nullptr)
2280            continue;
2281        const CString& kernelName = assembler.kernels[i].name;
2282        AsmROCmKernelConfig& config = *kernel.config.get();
2283        // setup config
2284        // fill default values
2285        if (config.amdCodeVersionMajor == BINGEN_DEFAULT)
2286            config.amdCodeVersionMajor = 1;
2287        if (config.amdCodeVersionMinor == BINGEN_DEFAULT)
2288            config.amdCodeVersionMinor = 0;
2289        if (config.amdMachineKind == BINGEN16_DEFAULT)
2290            config.amdMachineKind = 1;
2291        if (config.amdMachineMajor == BINGEN16_DEFAULT)
2292            config.amdMachineMajor = amdGpuArchValues.major;
2293        if (config.amdMachineMinor == BINGEN16_DEFAULT)
2294            config.amdMachineMinor = amdGpuArchValues.minor;
2295        if (config.amdMachineStepping == BINGEN16_DEFAULT)
2296            config.amdMachineStepping = amdGpuArchValues.stepping;
2297        if (config.kernelCodeEntryOffset == BINGEN64_DEFAULT)
2298            config.kernelCodeEntryOffset = 256;
2299        if (config.kernelCodePrefetchOffset == BINGEN64_DEFAULT)
2300            config.kernelCodePrefetchOffset = 0;
2301        if (config.kernelCodePrefetchSize == BINGEN64_DEFAULT)
2302            config.kernelCodePrefetchSize = 0;
2303        if (config.maxScrachBackingMemorySize == BINGEN64_DEFAULT) // ??
2304            config.maxScrachBackingMemorySize = 0;
2305       
2306        if (config.workitemPrivateSegmentSize == BINGEN_DEFAULT) // scratch buffer
2307            config.workitemPrivateSegmentSize =  0;
2308        if (config.workgroupGroupSegmentSize == BINGEN_DEFAULT) // local size
2309            config.workgroupGroupSegmentSize = 0;
2310        if (config.gdsSegmentSize == BINGEN_DEFAULT)
2311            config.gdsSegmentSize = 0;
2312        if (config.kernargSegmentSize == BINGEN64_DEFAULT)
2313            config.kernargSegmentSize = 0;
2314        if (config.workgroupFbarrierCount == BINGEN_DEFAULT)
2315            config.workgroupFbarrierCount = 0;
2316        if (config.reservedVgprFirst == BINGEN16_DEFAULT)
2317            config.reservedVgprFirst = 0;
2318        if (config.reservedVgprCount == BINGEN16_DEFAULT)
2319            config.reservedVgprCount = 0;
2320        if (config.reservedSgprFirst == BINGEN16_DEFAULT)
2321            config.reservedSgprFirst = 0;
2322        if (config.reservedSgprCount == BINGEN16_DEFAULT)
2323            config.reservedSgprCount = 0;
2324        if (config.debugWavefrontPrivateSegmentOffsetSgpr == BINGEN16_DEFAULT)
2325            config.debugWavefrontPrivateSegmentOffsetSgpr = 0;
2326        if (config.debugPrivateSegmentBufferSgpr == BINGEN16_DEFAULT)
2327            config.debugPrivateSegmentBufferSgpr = 0;
2328        if (config.kernargSegmentAlignment == BINGEN8_DEFAULT)
2329            config.kernargSegmentAlignment = 4; // 16 bytes
2330        if (config.groupSegmentAlignment == BINGEN8_DEFAULT)
2331            config.groupSegmentAlignment = 4; // 16 bytes
2332        if (config.privateSegmentAlignment == BINGEN8_DEFAULT)
2333            config.privateSegmentAlignment = 4; // 16 bytes
2334        if (config.wavefrontSize == BINGEN8_DEFAULT)
2335            config.wavefrontSize = 6; // 64 threads
2336       
2337        cxuint userSGPRsNum = 0;
2338        if (config.userDataNum == BINGEN8_DEFAULT)
2339        {
2340            // calcuate userSGPRs
2341            const uint16_t sgprFlags = config.enableSgprRegisterFlags;
2342            userSGPRsNum =
2343                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_BUFFER)!=0 ? 4 : 0) +
2344                ((sgprFlags&ROCMFLAG_USE_DISPATCH_PTR)!=0 ? 2 : 0) +
2345                ((sgprFlags&ROCMFLAG_USE_QUEUE_PTR)!=0 ? 2 : 0) +
2346                ((sgprFlags&ROCMFLAG_USE_KERNARG_SEGMENT_PTR)!=0 ? 2 : 0) +
2347                ((sgprFlags&ROCMFLAG_USE_DISPATCH_ID)!=0 ? 2 : 0) +
2348                ((sgprFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0 ? 2 : 0) +
2349                ((sgprFlags&ROCMFLAG_USE_PRIVATE_SEGMENT_SIZE)!=0) +
2350                /* use_grid_workgroup_count */
2351                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_X)!=0) +
2352                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Y)!=0) +
2353                ((sgprFlags&ROCMFLAG_USE_GRID_WORKGROUP_COUNT_Z)!=0);
2354           userSGPRsNum = std::min(16U, userSGPRsNum);
2355        }
2356        else // default
2357            userSGPRsNum = config.userDataNum;
2358       
2359        /* include userData sgprs */
2360        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
2361                ((config.computePgmRsrc2>>7)&7);
2362        // extra sgprs for dimensions
2363        cxuint minRegsNum[2];
2364        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
2365                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
2366                   ((config.workitemPrivateSegmentSize!=0) ?
2367                           GPUSETUP_SCRATCH_EN : 0), minRegsNum);
2368       
2369        if (config.usedSGPRsNum!=BINGEN_DEFAULT && maxSGPRsNum < config.usedSGPRsNum)
2370        {
2371            // check only if sgprsnum set explicitly
2372            char numBuf[64];
2373            snprintf(numBuf, 64, "(max %u)", maxSGPRsNum);
2374            assembler.printError(assembler.kernels[i].sourcePos, (std::string(
2375                    "Number of total SGPRs for kernel '")+
2376                    kernelName.c_str()+"' is too high "+numBuf).c_str());
2377            good = false;
2378        }
2379        // set usedSGPRsNum
2380        if (config.usedSGPRsNum==BINGEN_DEFAULT)
2381        {
2382            cxuint flags = kernelStates[i]->allocRegFlags |
2383                // flat_scratch_init
2384                ((config.enableSgprRegisterFlags&ROCMFLAG_USE_FLAT_SCRATCH_INIT)!=0?
2385                            GCN_FLAT : 0) |
2386                // enable_xnack
2387                ((config.enableFeatureFlags&ROCMFLAG_USE_XNACK_ENABLED)!=0 ?
2388                            GCN_XNACK : 0);
2389            config.usedSGPRsNum = std::min(
2390                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]) +
2391                    getGPUExtraRegsNum(arch, REGTYPE_SGPR, flags|GCN_VCC),
2392                    maxSGPRsNum); // include all extra sgprs
2393        }
2394        // set usedVGPRsNum
2395        if (config.usedVGPRsNum==BINGEN_DEFAULT)
2396            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
2397       
2398        cxuint sgprsNum = std::max(config.usedSGPRsNum, 1U);
2399        cxuint vgprsNum = std::max(config.usedVGPRsNum, 1U);
2400        // computePGMRSRC1
2401        config.computePgmRsrc1 |= calculatePgmRSrc1(arch, vgprsNum, sgprsNum,
2402                        config.priority, config.floatMode, config.privilegedMode,
2403                        config.dx10Clamp, config.debugMode, config.ieeeMode);
2404        // computePGMRSRC2
2405        config.computePgmRsrc2 = (config.computePgmRsrc2 & 0xffffe440U) |
2406                calculatePgmRSrc2(arch, (config.workitemPrivateSegmentSize != 0),
2407                            userSGPRsNum, false, config.dimMask,
2408                            (config.computePgmRsrc2 & 0x1b80U), config.tgSize,
2409                            config.workgroupGroupSegmentSize, config.exceptions);
2410       
2411        if (config.wavefrontSgprCount == BINGEN16_DEFAULT)
2412            config.wavefrontSgprCount = sgprsNum;
2413        if (config.workitemVgprCount == BINGEN16_DEFAULT)
2414            config.workitemVgprCount = vgprsNum;
2415       
2416        if (config.callConvention == BINGEN_DEFAULT)
2417            config.callConvention = 0;
2418        if (config.runtimeLoaderKernelSymbol == BINGEN64_DEFAULT)
2419            config.runtimeLoaderKernelSymbol = 0;
2420       
2421        config.toLE(); // to little-endian
2422        // put control directive section to config
2423        if (kernel.ctrlDirSection!=ASMSECT_NONE &&
2424            assembler.sections[kernel.ctrlDirSection].content.size()==128)
2425            ::memcpy(config.controlDirective, 
2426                 assembler.sections[kernel.ctrlDirSection].content.data(), 128);
2427    }
2428   
2429    // if set adds symbols to binary
2430    std::vector<ROCmSymbolInput> dataSymbols;
2431    if (assembler.getFlags() & ASM_FORCE_ADD_SYMBOLS)
2432        for (const AsmSymbolEntry& symEntry: assembler.globalScope.symbolMap)
2433        {
2434            if (!symEntry.second.hasValue)
2435                continue; // unresolved
2436            if (ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
2437                continue; // local
2438            if (assembler.kernelMap.find(symEntry.first.c_str())!=assembler.kernelMap.end())
2439                continue; // if kernel name
2440           
2441            if (symEntry.second.sectionId==codeSection)
2442            {
2443                // put data objects
2444                dataSymbols.push_back({symEntry.first, size_t(symEntry.second.value),
2445                    size_t(symEntry.second.size), ROCmRegionType::DATA});
2446                continue;
2447            }
2448           
2449            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
2450                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
2451            if (binSectId==ELFSECTID_UNDEF)
2452                continue; // no section
2453           
2454            output.extraSymbols.push_back({ symEntry.first, symEntry.second.value,
2455                    symEntry.second.size, binSectId, false, symEntry.second.info,
2456                    symEntry.second.other });
2457        }
2458   
2459    AsmSection& asmCSection = assembler.sections[codeSection];
2460    const AsmSymbolMap& symbolMap = assembler.getSymbolMap();
2461    for (size_t ki = 0; ki < output.symbols.size(); ki++)
2462    {
2463        ROCmSymbolInput& kinput = output.symbols[ki];
2464        auto it = symbolMap.find(kinput.symbolName);
2465        if (it == symbolMap.end() || !it->second.isDefined())
2466        {
2467            // error, undefined
2468            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2469                        "Symbol for kernel '")+kinput.symbolName.c_str()+
2470                        "' is undefined").c_str());
2471            good = false;
2472            continue;
2473        }
2474        const AsmSymbol& symbol = it->second;
2475        if (!symbol.hasValue)
2476        {
2477            // error, unresolved
2478            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2479                    "Symbol for kernel '") + kinput.symbolName.c_str() +
2480                    "' is not resolved").c_str());
2481            good = false;
2482            continue;
2483        }
2484        if (symbol.sectionId != codeSection)
2485        {
2486            /// error, wrong section
2487            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2488                    "Symbol for kernel '")+kinput.symbolName.c_str()+
2489                    "' is defined for section other than '.text'").c_str());
2490            good = false;
2491            continue;
2492        }
2493        const Kernel& kernel = *kernelStates[ki];
2494        kinput.offset = symbol.value;
2495       
2496        if (asmCSection.content.size() < symbol.value + sizeof(ROCmKernelConfig))
2497        {
2498            // if kernel configuration out of section size
2499            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
2500                "Code for kernel '")+kinput.symbolName.c_str()+
2501                "' is too small for configuration").c_str());
2502            good = false;
2503            continue;
2504        }
2505        else if (kernel.config!=nullptr)
2506            // put config to code section
2507            ::memcpy(asmCSection.content.data() + symbol.value,
2508                     kernel.config.get(), sizeof(ROCmKernelConfig));
2509        // set symbol type
2510        kinput.type = kernel.isFKernel ? ROCmRegionType::FKERNEL : ROCmRegionType::KERNEL;
2511    }
2512   
2513    // put data objects
2514    dataSymbols.insert(dataSymbols.end(), output.symbols.begin(), output.symbols.end());
2515    output.symbols = std::move(dataSymbols);
2516    return good;
2517}
2518
2519void AsmROCmHandler::writeBinary(std::ostream& os) const
2520{
2521    ROCmBinGenerator binGenerator(&output);
2522    binGenerator.generate(os);
2523}
2524
2525void AsmROCmHandler::writeBinary(Array<cxbyte>& array) const
2526{
2527    ROCmBinGenerator binGenerator(&output);
2528    binGenerator.generate(array);
2529}
Note: See TracBrowser for help on using the repository browser.