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

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

CLRadeonExtender: DisasmAmd?&DisasmROCm: Check arg types and other fields before printing.
ROCmMetadata: Check arg types and other fields before generating. Escape number in string fields.
AsmROCm: Add additional pseudo-ops (only names) to set metadata info.

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