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

Last change on this file since 3728 was 3728, checked in by matszpk, 22 months ago

CLRadeonExtender: DisasmROCm: always print argument name.
AsmROCm: Tentative and untested version of the stuff to handle ROCm metadata (with kernel arguments).

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