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

Last change on this file since 3727 was 3727, checked in by matszpk, 22 months ago

CLRadeonExtender: AsmGallium?: Remove obsolete (stupid) checking spilled GPRs.
AsmROCm: Add first stuff to handling ROCm metadata config. ROCmBin: Checking uniqueness of printf ids.

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