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

Last change on this file since 3900 was 3900, checked in by matszpk, 13 months ago

CLRadeonExtender: AsmROCm: Add '.nosectdiffs' for compatibility with the ROCm behaviour from older assembler's versions.

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