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

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

CLRadeonExtender: AsmROCm: Allow to place '.printf' and '.md_version' anywhere in code.

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