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

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

CLRadeonExtender: Asm: First working AsmROCm with section differences.

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