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

Last change on this file since 3829 was 3829, checked in by matszpk, 14 months ago

CLRadeonExtender: AsmROCm: Add shortcuts to access qualifiers (rdonly, wronly, rdwr).

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