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

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

CLRadeonExtender: ROCm: Replace '.md_spilledsgprs' and '.md_spilledvgprs' by '.spilledsgprs' and '.spilledvgprs'.

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