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

Last change on this file since 2604 was 2604, checked in by matszpk, 3 years ago

CLRadeonExtender: AsmROCm: tentative version of code to setup kernel configuration.
Fixed setting alignments and wavefront size (power of 2). Add extra symbols to output.
GPUId: Add AMDGPUArchValues to GPUId.

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