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

Last change on this file since 3294 was 3294, checked in by matszpk, 16 months ago

CLRadeonExtender: AsmROCm: Do not print warnings about out of range when values was not parsed in
'.codeversion' and '.machine' pseudo-ops. fix typos. Small formatting in AsmGalliumFormat?.

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