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

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

CLRadeonExtender: AsmROCm: Next prepping before implementing section diffs.

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