source: CLRX/CLRadeonExtender/trunk/amdasm/AsmAmdFormat.cpp @ 3755

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

CLRadeonExtender: Asm: Make first argument in CWS ('.cws', 'reqd_work_group_size' ...) as optional.
CLRXDocs: Update syntax for '.cws' and other pseudo-ops with group-size. Fixed formatting.

File size: 71.0 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cstdio>
22#include <cstring>
23#include <string>
24#include <vector>
25#include <utility>
26#include <algorithm>
27#include <CLRX/utils/Utilities.h>
28#include <CLRX/amdasm/Assembler.h>
29#include <CLRX/amdasm/AsmFormats.h>
30#include "AsmAmdInternals.h"
31
32using namespace CLRX;
33
34// all AMD Catalyst pseudo-op names (sorted)
35static const char* amdPseudoOpNamesTbl[] =
36{
37    "arg", "boolconsts", "calnote", "cbid",
38    "cbmask", "compile_options", "condout", "config",
39    "constantbuffers", "cws", "dims", "driver_info", "driver_version",
40    "earlyexit", "entry", "exceptions",
41    "floatconsts", "floatmode", "get_driver_version",
42    "globalbuffers", "globaldata", "header", "hwlocal",
43    "hwregion", "ieeemode", "inputs", "inputsamplers",
44    "intconsts", "localsize", "metadata", "outputs", "persistentbuffers",
45    "pgmrsrc2", "printfid", "privateid", "proginfo",
46    "reqd_work_group_size",
47    "sampler", "scratchbuffer", "scratchbuffers", "segment",
48    "sgprsnum", "subconstantbuffers", "tgsize", "uav", "uavid",
49    "uavmailboxsize", "uavopmask", "uavprivate", "useconstdata",
50    "useprintf", "userdata", "vgprsnum"
51};
52
53// all AMD Catalyst pseudo-op names (sorted)
54enum
55{
56    AMDOP_ARG = 0, AMDOP_BOOLCONSTS, AMDOP_CALNOTE, AMDOP_CBID,
57    AMDOP_CBMASK, AMDOP_COMPILE_OPTIONS, AMDOP_CONDOUT, AMDOP_CONFIG,
58    AMDOP_CONSTANTBUFFERS, AMDOP_CWS, AMDOP_DIMS, AMDOP_DRIVER_INFO, AMDOP_DRIVER_VERSION,
59    AMDOP_EARLYEXIT, AMDOP_ENTRY, AMDOP_EXCEPTIONS,
60    AMDOP_FLOATCONSTS, AMDOP_FLOATMODE, AMDOP_GETDRVVER,
61    AMDOP_GLOBALBUFFERS, AMDOP_GLOBALDATA, AMDOP_HEADER, AMDOP_HWLOCAL,
62    AMDOP_HWREGION, AMDOP_IEEEMODE, AMDOP_INPUTS, AMDOP_INPUTSAMPLERS,
63    AMDOP_INTCONSTS, AMDOP_LOCALSIZE, AMDOP_METADATA,
64    AMDOP_OUTPUTS,AMDOP_PERSISTENTBUFFERS, AMDOP_PGMRSRC2,
65    AMDOP_PRINTFID, AMDOP_PRIVATEID, AMDOP_PROGINFO,
66    AMDOP_REQD_WORK_GROUP_SIZE,
67    AMDOP_SAMPLER, AMDOP_SCRATCHBUFFER, AMDOP_SCRATCHBUFFERS, AMDOP_SEGMENT,
68    AMDOP_SGPRSNUM, AMDOP_SUBCONSTANTBUFFERS, AMDOP_TGSIZE, AMDOP_UAV, AMDOP_UAVID,
69    AMDOP_UAVMAILBOXSIZE, AMDOP_UAVOPMASK, AMDOP_UAVPRIVATE, AMDOP_USECONSTDATA,
70    AMDOP_USEPRINTF, AMDOP_USERDATA, AMDOP_VGPRSNUM
71};
72
73/*
74 * AmdCatalyst format handler
75 */
76
77AsmAmdHandler::AsmAmdHandler(Assembler& assembler) : AsmFormatHandler(assembler),
78                output{}, dataSection(0), extraSectionCount(0)
79{
80    assembler.currentKernel = ASMKERN_GLOBAL;
81    assembler.currentSection = 0;
82    // first, add global data section (will be default)
83    sections.push_back({ ASMKERN_GLOBAL, AsmSectionType::DATA, ELFSECTID_UNDEF, nullptr });
84    savedSection = 0;
85    // detect amd driver version once, for using many times
86    detectedDriverVersion = detectAmdDriverVersion();
87}
88
89AsmAmdHandler::~AsmAmdHandler()
90{
91    for (Kernel* kernel: kernelStates)
92        delete kernel;
93}
94
95// routine to deterime driver version while assemblying
96cxuint AsmAmdHandler::determineDriverVersion() const
97{
98    if (output.driverVersion==0 && output.driverInfo.empty())
99    {
100        if (assembler.getDriverVersion() == 0)
101            return detectedDriverVersion;
102        else
103            return assembler.getDriverVersion();
104    }
105    else
106        return output.driverVersion;
107}
108
109void AsmAmdHandler::saveCurrentSection()
110{
111    /// save previous section
112    if (assembler.currentKernel == ASMKERN_GLOBAL)
113        savedSection = assembler.currentSection;
114    else
115        kernelStates[assembler.currentKernel]->savedSection = assembler.currentSection;
116}
117
118
119void AsmAmdHandler::restoreCurrentAllocRegs()
120{
121    if (assembler.currentKernel!=ASMKERN_GLOBAL &&
122        assembler.currentSection==kernelStates[assembler.currentKernel]->codeSection)
123        assembler.isaAssembler->setAllocatedRegisters(
124                kernelStates[assembler.currentKernel]->allocRegs,
125                kernelStates[assembler.currentKernel]->allocRegFlags);
126}
127
128void AsmAmdHandler::saveCurrentAllocRegs()
129{
130    if (assembler.currentKernel!=ASMKERN_GLOBAL &&
131        assembler.currentSection==kernelStates[assembler.currentKernel]->codeSection)
132    {
133        size_t num;
134        cxuint* destRegs = kernelStates[assembler.currentKernel]->allocRegs;
135        const cxuint* regs = assembler.isaAssembler->getAllocatedRegisters(num,
136                       kernelStates[assembler.currentKernel]->allocRegFlags);
137        std::copy(regs, regs + num, destRegs);
138    }
139}
140
141cxuint AsmAmdHandler::addKernel(const char* kernelName)
142{
143    cxuint thisKernel = output.kernels.size();
144    cxuint thisSection = sections.size();
145    output.addEmptyKernel(kernelName);
146    Kernel kernelState{ ASMSECT_NONE, ASMSECT_NONE, ASMSECT_NONE,
147            thisSection, ASMSECT_NONE };
148    kernelState.extraSectionCount = 0;
149    /* add new kernel and their section (.text) */
150    kernelStates.push_back(new Kernel(std::move(kernelState)));
151    sections.push_back({ thisKernel, AsmSectionType::CODE, ELFSECTID_TEXT, ".text" });
152   
153    saveCurrentAllocRegs();
154    saveCurrentSection();
155   
156    assembler.currentKernel = thisKernel;
157    assembler.currentSection = thisSection;
158    assembler.isaAssembler->setAllocatedRegisters();
159    return thisKernel;
160}
161
162cxuint AsmAmdHandler::addSection(const char* sectionName, cxuint kernelId)
163{
164    const cxuint thisSection = sections.size();
165    Section section;
166    section.kernelId = kernelId;
167    if (::strcmp(sectionName, ".data") == 0)
168    {
169        // .data section (only in kernels)
170        if (kernelId == ASMKERN_GLOBAL)
171            throw AsmFormatException("Section '.data' permitted only inside kernels");
172        kernelStates[kernelId]->dataSection = thisSection;
173        section.type = AsmSectionType::DATA;
174        section.elfBinSectId = ELFSECTID_DATA;
175        section.name = ".data"; // set static name (available by whole lifecycle)*/
176    }
177    else if (kernelId == ASMKERN_GLOBAL)
178    {
179        // add extra section to main binary
180        auto out = extraSectionMap.insert(std::make_pair(std::string(sectionName),
181                    thisSection));
182        if (!out.second)
183            throw AsmFormatException("Section already exists");
184        section.type = AsmSectionType::EXTRA_SECTION;
185        section.elfBinSectId = extraSectionCount++;
186        /// referfence entry is available and unchangeable by whole lifecycle of section map
187        section.name = out.first->first.c_str();
188    }
189    else
190    {
191        /* inside kernel binary */
192        if (kernelId >= kernelStates.size())
193            throw AsmFormatException("KernelId out of range");
194        Kernel& kernelState = *kernelStates[kernelId];
195        auto out = kernelState.extraSectionMap.insert(std::make_pair(
196                    CString(sectionName), thisSection));
197        if (!out.second)
198            throw AsmFormatException("Section already exists");
199        section.type = AsmSectionType::EXTRA_SECTION;
200        section.elfBinSectId = kernelState.extraSectionCount++;
201        /// referfence entry is available and unchangeable by whole lifecycle of section map
202        section.name = out.first->first.c_str();
203    }
204    sections.push_back(section);
205   
206    saveCurrentAllocRegs();
207    saveCurrentSection();
208   
209    assembler.currentKernel = kernelId;
210    assembler.currentSection = thisSection;
211   
212    restoreCurrentAllocRegs();
213    return thisSection;
214}
215
216cxuint AsmAmdHandler::getSectionId(const char* sectionName) const
217{
218    if (assembler.currentKernel == ASMKERN_GLOBAL)
219    {
220        // get extra section from main binary
221        SectionMap::const_iterator it = extraSectionMap.find(sectionName);
222        if (it != extraSectionMap.end())
223            return it->second;
224        return ASMSECT_NONE;
225    }
226    else
227    {
228        const Kernel& kernelState = *kernelStates[assembler.currentKernel];
229        if (::strcmp(sectionName, ".text") == 0)
230            return kernelState.codeSection;
231        else if (::strcmp(sectionName, ".data") == 0)
232            return kernelState.dataSection;
233        else
234        {
235            // if extra section, the find it
236            SectionMap::const_iterator it = kernelState.extraSectionMap.find(sectionName);
237            if (it != kernelState.extraSectionMap.end())
238                return it->second;
239        }
240        return ASMSECT_NONE;
241    }
242}
243
244void AsmAmdHandler::setCurrentKernel(cxuint kernel)
245{
246    if (kernel != ASMKERN_GLOBAL && kernel >= kernelStates.size())
247        throw AsmFormatException("KernelId out of range");
248   
249    saveCurrentAllocRegs();
250    saveCurrentSection();
251    assembler.currentKernel = kernel;
252    if (kernel != ASMKERN_GLOBAL)
253        assembler.currentSection = kernelStates[kernel]->savedSection;
254    else
255        assembler.currentSection = savedSection;
256    restoreCurrentAllocRegs();
257}
258
259void AsmAmdHandler::setCurrentSection(cxuint sectionId)
260{
261    if (sectionId >= sections.size())
262        throw AsmFormatException("SectionId out of range");
263   
264    saveCurrentAllocRegs();
265    saveCurrentSection();
266    assembler.currentKernel = sections[sectionId].kernelId;
267    assembler.currentSection = sectionId;
268    restoreCurrentAllocRegs();
269}
270
271AsmFormatHandler::SectionInfo AsmAmdHandler::getSectionInfo(cxuint sectionId) const
272{
273    /* find section */
274    if (sectionId >= sections.size())
275        throw AsmFormatException("Section doesn't exists");
276    AsmFormatHandler::SectionInfo info;
277    info.type = sections[sectionId].type;
278    info.flags = 0;
279    // code is addressable and writeable
280    if (info.type == AsmSectionType::CODE)
281        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE;
282    // any other section (except config) are absolute addressable and writeable
283    else if (info.type != AsmSectionType::CONFIG)
284        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE | ASMSECT_ABS_ADDRESSABLE;
285    info.name = sections[sectionId].name;
286    return info;
287}
288
289namespace CLRX
290{
291
292bool AsmAmdPseudoOps::checkPseudoOpName(const CString& string)
293{
294    if (string.empty() || string[0] != '.')
295        return false;
296    const size_t pseudoOp = binaryFind(amdPseudoOpNamesTbl, amdPseudoOpNamesTbl +
297                sizeof(amdPseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
298               CStringLess()) - amdPseudoOpNamesTbl;
299    return pseudoOp < sizeof(amdPseudoOpNamesTbl)/sizeof(char*);
300}
301
302void AsmAmdPseudoOps::setCompileOptions(AsmAmdHandler& handler, const char* linePtr)
303{
304    Assembler& asmr = handler.assembler;
305    const char* end = asmr.line + asmr.lineSize;
306    skipSpacesToEnd(linePtr, end);
307    std::string out;
308    if (!asmr.parseString(out, linePtr))
309        return;
310    if (!checkGarbagesAtEnd(asmr, linePtr))
311        return;
312    handler.output.compileOptions = out;
313}
314
315void AsmAmdPseudoOps::setDriverInfo(AsmAmdHandler& handler, const char* linePtr)
316{
317    Assembler& asmr = handler.assembler;
318    const char* end = asmr.line + asmr.lineSize;
319    skipSpacesToEnd(linePtr, end);
320    std::string out;
321    if (!asmr.parseString(out, linePtr))
322        return;
323    if (!checkGarbagesAtEnd(asmr, linePtr))
324        return;
325    handler.output.driverInfo = out;
326}
327
328void AsmAmdPseudoOps::setDriverVersion(AsmAmdHandler& handler, const char* linePtr)
329{
330    Assembler& asmr = handler.assembler;
331    const char* end = asmr.line + asmr.lineSize;
332    skipSpacesToEnd(linePtr, end);
333    uint64_t value;
334    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
335        return;
336    if (!checkGarbagesAtEnd(asmr, linePtr))
337        return;
338    handler.output.driverVersion = value;
339}
340
341void AsmAmdPseudoOps::getDriverVersion(AsmAmdHandler& handler, const char* linePtr)
342{
343    AsmParseUtils::setSymbolValue(handler.assembler, linePtr,
344                handler.determineDriverVersion(), ASMSECT_ABS);
345}
346
347void AsmAmdPseudoOps::doGlobalData(AsmAmdHandler& handler, const char* pseudoOpPlace,
348                      const char* linePtr)
349{
350    Assembler& asmr = handler.assembler;
351    if (!checkGarbagesAtEnd(asmr, linePtr))
352        return;
353   
354    if (handler.dataSection==ASMSECT_NONE)
355    {
356        /* add this section */
357        cxuint thisSection = handler.sections.size();
358        handler.sections.push_back({ ASMKERN_GLOBAL,  AsmSectionType::DATA,
359            ELFSECTID_UNDEF, nullptr });
360        handler.dataSection = thisSection;
361    }
362    asmr.goToSection(pseudoOpPlace, handler.dataSection);
363}
364
365void AsmAmdPseudoOps::addMetadata(AsmAmdHandler& handler, const char* pseudoOpPlace,
366                      const char* linePtr)
367{
368    Assembler& asmr = handler.assembler;
369    if (asmr.currentKernel==ASMKERN_GLOBAL)
370        PSEUDOOP_RETURN_BY_ERROR("Metadata can be defined only inside kernel")
371    if (handler.kernelStates[asmr.currentKernel]->configSection!=ASMSECT_NONE)
372        PSEUDOOP_RETURN_BY_ERROR("Metadata can't be defined if configuration was defined")
373   
374    if (!checkGarbagesAtEnd(asmr, linePtr))
375        return;
376   
377    cxuint& metadataSection = handler.kernelStates[asmr.currentKernel]->metadataSection;
378    if (metadataSection == ASMSECT_NONE)
379    {
380        /* add this section */
381        cxuint thisSection = handler.sections.size();
382        handler.sections.push_back({ asmr.currentKernel, AsmSectionType::AMD_METADATA,
383            ELFSECTID_UNDEF, nullptr });
384        metadataSection = thisSection;
385    }
386    asmr.goToSection(pseudoOpPlace, metadataSection);
387}
388
389void AsmAmdPseudoOps::doConfig(AsmAmdHandler& handler, const char* pseudoOpPlace,
390                      const char* linePtr)
391{
392    Assembler& asmr = handler.assembler;
393    if (asmr.currentKernel==ASMKERN_GLOBAL)
394        PSEUDOOP_RETURN_BY_ERROR("Kernel config can be defined only inside kernel")
395    AsmAmdHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
396    if (kernel.metadataSection!=ASMSECT_NONE || kernel.headerSection!=ASMSECT_NONE ||
397        !kernel.calNoteSections.empty())
398        PSEUDOOP_RETURN_BY_ERROR("Config can't be defined if metadata,header and/or"
399                        " CALnotes section exists")
400
401    if (!checkGarbagesAtEnd(asmr, linePtr))
402        return;
403       
404    if (kernel.configSection == ASMSECT_NONE)
405    {
406        /* add this section */
407        cxuint thisSection = handler.sections.size();
408        handler.sections.push_back({ asmr.currentKernel, AsmSectionType::CONFIG,
409            ELFSECTID_UNDEF, nullptr });
410        kernel.configSection = thisSection;
411    }
412    asmr.goToSection(pseudoOpPlace, kernel.configSection);
413    handler.output.kernels[asmr.currentKernel].useConfig = true;
414}
415
416static const uint32_t singleValueCALNotesMask =
417        (1U<<CALNOTE_ATI_EARLYEXIT) | (1U<<CALNOTE_ATI_CONDOUT) |
418        (1U<<CALNOTE_ATI_UAV_OP_MASK) | (1U<<CALNOTE_ATI_UAV_MAILBOX_SIZE);
419
420void AsmAmdPseudoOps::addCALNote(AsmAmdHandler& handler, const char* pseudoOpPlace,
421                      const char* linePtr, uint32_t calNoteId)
422{
423    Assembler& asmr = handler.assembler;
424    const char* end = asmr.line + asmr.lineSize;
425    if (asmr.currentKernel==ASMKERN_GLOBAL)
426        PSEUDOOP_RETURN_BY_ERROR("CALNote can be defined only inside kernel")
427    AsmAmdHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
428    if (kernel.configSection!=ASMSECT_NONE)
429        PSEUDOOP_RETURN_BY_ERROR("CALNote can't be defined if configuration was defined")
430   
431    skipSpacesToEnd(linePtr, end);
432    uint64_t value = 0;
433    const char* valuePlace = linePtr;
434    // check whether CAL note hold only single value
435    const bool singleValue = calNoteId < 32 &&
436            (singleValueCALNotesMask & (1U<<calNoteId)) && linePtr != end;
437    if (singleValue)
438    {
439        /* if pseudo-op for this calnote accept single 32-bit value */
440        if (!getAbsoluteValueArg(asmr, value, linePtr, false))
441            return; // error
442        asmr.printWarningForRange(32, value, asmr.getSourcePos(valuePlace));
443    }
444    if (!checkGarbagesAtEnd(asmr, linePtr))
445        return;
446   
447    // always add new CALnote
448    const cxuint thisSection = handler.sections.size();
449    handler.sections.push_back({ asmr.currentKernel, AsmSectionType::AMD_CALNOTE,
450            ELFSECTID_UNDEF, nullptr, calNoteId });
451    kernel.calNoteSections.push_back({thisSection});
452    asmr.goToSection(pseudoOpPlace, thisSection);
453   
454    if (singleValue)
455    {
456        // with single value
457        uint32_t outValue = LEV(uint32_t(value));
458        asmr.putData(4, (const cxbyte*)&outValue);
459    }
460}
461
462void AsmAmdPseudoOps::addCustomCALNote(AsmAmdHandler& handler, const char* pseudoOpPlace,
463                      const char* linePtr)
464{
465    Assembler& asmr = handler.assembler;
466    const char* end = asmr.line + asmr.lineSize;
467    uint64_t value;
468   
469    if (asmr.currentKernel==ASMKERN_GLOBAL)
470        PSEUDOOP_RETURN_BY_ERROR("CALNote can be defined only inside kernel")
471    AsmAmdHandler::Kernel& kernel = *handler.kernelStates[asmr.currentKernel];
472    if (kernel.configSection!=ASMSECT_NONE)
473        PSEUDOOP_RETURN_BY_ERROR("CALNote can't be defined if configuration was defined")
474   
475    skipSpacesToEnd(linePtr, end);
476    const char* valuePlace = linePtr;
477    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
478        return;
479    asmr.printWarningForRange(32, value, asmr.getSourcePos(valuePlace), WS_UNSIGNED);
480    // resue code in addCALNote
481    addCALNote(handler, pseudoOpPlace, linePtr, value);
482}
483
484void AsmAmdPseudoOps::addHeader(AsmAmdHandler& handler, const char* pseudoOpPlace,
485                  const char* linePtr)
486{
487    Assembler& asmr = handler.assembler;
488    if (asmr.currentKernel==ASMKERN_GLOBAL)
489        PSEUDOOP_RETURN_BY_ERROR("Header can be defined only inside kernel")
490    if (handler.kernelStates[asmr.currentKernel]->configSection!=ASMSECT_NONE)
491        PSEUDOOP_RETURN_BY_ERROR("Header can't be defined if configuration was defined")
492   
493    if (!checkGarbagesAtEnd(asmr, linePtr))
494        return;
495   
496    cxuint& headerSection = handler.kernelStates[asmr.currentKernel]->headerSection;
497    if (headerSection == ASMSECT_NONE)
498    {
499        /* add this section */
500        cxuint thisSection = handler.sections.size();
501        handler.sections.push_back({ asmr.currentKernel, AsmSectionType::AMD_HEADER,
502            ELFSECTID_UNDEF, nullptr });
503        headerSection = thisSection;
504    }
505    asmr.goToSection(pseudoOpPlace, headerSection);
506}
507
508void AsmAmdPseudoOps::doEntry(AsmAmdHandler& handler, const char* pseudoOpPlace,
509              const char* linePtr, uint32_t requiredCalNoteIdMask, const char* entryName)
510{
511    Assembler& asmr = handler.assembler;
512    const char* end = asmr.line + asmr.lineSize;
513   
514    /* check place where is entry */
515    if (asmr.currentKernel==ASMKERN_GLOBAL ||
516        handler.sections[asmr.currentSection].type != AsmSectionType::AMD_CALNOTE ||
517        (handler.sections[asmr.currentSection].extraId >= 32 ||
518        ((1U<<handler.sections[asmr.currentSection].extraId) & requiredCalNoteIdMask))==0)
519        PSEUDOOP_RETURN_BY_ERROR((std::string("Illegal place of ")+entryName).c_str())
520   
521    if (handler.sections[asmr.currentSection].extraId == CALNOTE_ATI_UAV)
522    {
523        // special version for uav (four values per entry)
524        doUavEntry(handler, pseudoOpPlace, linePtr);
525        return;
526    }
527   
528    skipSpacesToEnd(linePtr, end);
529    const char* value1Place = linePtr;
530    uint64_t value1 = 0, value2 = 0;
531    // parse address (first value)
532    bool good = getAbsoluteValueArg(asmr, value1, linePtr, true);
533    if (good)
534        asmr.printWarningForRange(32, value1, asmr.getSourcePos(value1Place));
535   
536    if (!skipRequiredComma(asmr, linePtr))
537        return;
538    const char* value2Place = linePtr;
539    // parse value (second value)
540    if (getAbsoluteValueArg(asmr, value2, linePtr, true))
541        asmr.printWarningForRange(32, value2, asmr.getSourcePos(value2Place));
542    else
543        good = false;
544   
545    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
546        return;
547   
548    uint32_t outVals[2];
549    SLEV(outVals[0], value1);
550    SLEV(outVals[1], value2);
551    asmr.putData(8, (const cxbyte*)outVals);
552}
553
554void AsmAmdPseudoOps::doUavEntry(AsmAmdHandler& handler, const char* pseudoOpPlace,
555                      const char* linePtr)
556{
557    Assembler& asmr = handler.assembler;
558    const char* end = asmr.line + asmr.lineSize;
559   
560    skipSpacesToEnd(linePtr, end);
561    const char* valuePlace = linePtr;
562    uint64_t value1 = 0, value2 = 0, value3 = 0, value4 = 0;
563    bool good = getAbsoluteValueArg(asmr, value1, linePtr, true);
564    if (good)
565        asmr.printWarningForRange(32, value1, asmr.getSourcePos(valuePlace));
566   
567    if (!skipRequiredComma(asmr, linePtr))
568        return;
569   
570    skipSpacesToEnd(linePtr, end);
571    valuePlace = linePtr;
572    if (getAbsoluteValueArg(asmr, value2, linePtr, true))
573        asmr.printWarningForRange(32, value2, asmr.getSourcePos(valuePlace));
574    else
575        good = false;
576   
577    if (!skipRequiredComma(asmr, linePtr))
578        return;
579   
580    skipSpacesToEnd(linePtr, end);
581    valuePlace = linePtr;
582    if (getAbsoluteValueArg(asmr, value3, linePtr, true))
583        asmr.printWarningForRange(32, value3, asmr.getSourcePos(valuePlace));
584    else
585        good = false;
586   
587    if (!skipRequiredComma(asmr, linePtr))
588        return;
589   
590    skipSpacesToEnd(linePtr, end);
591    valuePlace = linePtr;
592    if (getAbsoluteValueArg(asmr, value4, linePtr, true))
593        asmr.printWarningForRange(32, value4, asmr.getSourcePos(valuePlace));
594    else
595        good = false;
596   
597    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
598        return;
599   
600    uint32_t outVals[4];
601    SLEV(outVals[0], value1);
602    SLEV(outVals[1], value2);
603    SLEV(outVals[2], value3);
604    SLEV(outVals[3], value4);
605    asmr.putData(16, (const cxbyte*)outVals);
606}
607
608void AsmAmdPseudoOps::doCBId(AsmAmdHandler& handler, const char* pseudoOpPlace,
609                      const char* linePtr)
610{
611    Assembler& asmr = handler.assembler;
612    if (asmr.currentKernel!=ASMKERN_GLOBAL &&
613        asmr.sections[asmr.currentSection].type == AsmSectionType::CONFIG)
614        setConfigValue(handler, pseudoOpPlace, linePtr, AMDCVAL_CBID);
615    else // do entry (if no configuration)
616        doEntry(handler, pseudoOpPlace, linePtr, 1U<<CALNOTE_ATI_CONSTANT_BUFFERS, "cbid");
617}
618
619void AsmAmdPseudoOps::doCondOut(AsmAmdHandler& handler, const char* pseudoOpPlace,
620                      const char* linePtr)
621{
622    Assembler& asmr = handler.assembler;
623    if (asmr.currentKernel!=ASMKERN_GLOBAL &&
624        asmr.sections[asmr.currentSection].type == AsmSectionType::CONFIG)
625        setConfigValue(handler, pseudoOpPlace, linePtr, AMDCVAL_CONDOUT);
626    else // make calnote CONDOUT
627        addCALNote(handler, pseudoOpPlace, linePtr, CALNOTE_ATI_CONDOUT);
628}
629
630void AsmAmdPseudoOps::doEarlyExit(AsmAmdHandler& handler, const char* pseudoOpPlace,
631                      const char* linePtr)
632{
633    Assembler& asmr = handler.assembler;
634    if (asmr.currentKernel!=ASMKERN_GLOBAL &&
635        asmr.sections[asmr.currentSection].type == AsmSectionType::CONFIG)
636        setConfigValue(handler, pseudoOpPlace, linePtr, AMDCVAL_EARLYEXIT);
637    else // make calnote EARLYEXIT
638        addCALNote(handler, pseudoOpPlace, linePtr, CALNOTE_ATI_EARLYEXIT);
639}
640
641void AsmAmdPseudoOps::doSampler(AsmAmdHandler& handler, const char* pseudoOpPlace,
642                      const char* linePtr)
643{
644    Assembler& asmr = handler.assembler;
645    if (asmr.currentKernel!=ASMKERN_GLOBAL &&
646        asmr.sections[asmr.currentSection].type == AsmSectionType::CONFIG)
647    {
648        // accepts many values (this same format like
649        const char* end = asmr.line + asmr.lineSize;
650       
651        if (asmr.currentKernel==ASMKERN_GLOBAL ||
652            asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
653            PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
654       
655        AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
656       
657        skipSpacesToEnd(linePtr, end);
658        if (linePtr == end)
659            return; /* if no samplers */
660        do {
661            uint64_t value = 0;
662            const char* valuePlace = linePtr;
663            if (getAbsoluteValueArg(asmr, value, linePtr, true))
664            {
665                asmr.printWarningForRange(sizeof(cxuint)<<3, value,
666                                 asmr.getSourcePos(valuePlace), WS_UNSIGNED);
667                config.samplers.push_back(value);
668            }
669        } while(skipCommaForMultipleArgs(asmr, linePtr));
670        checkGarbagesAtEnd(asmr, linePtr);
671    }
672    else // add entry to input samplers CALNote
673        doEntry(handler, pseudoOpPlace, linePtr, 1U<<CALNOTE_ATI_INPUT_SAMPLERS, "sampler");
674}
675
676static const uint32_t argIsOptionalMask =  (1U<<AMDCVAL_PRIVATEID) |
677        (1U<<AMDCVAL_UAVID) | (1U<<AMDCVAL_CBID) | (1U<<AMDCVAL_PRINTFID);
678
679void AsmAmdPseudoOps::setConfigValue(AsmAmdHandler& handler, const char* pseudoOpPlace,
680                      const char* linePtr, AmdConfigValueTarget target)
681{
682    Assembler& asmr = handler.assembler;
683    const char* end = asmr.line + asmr.lineSize;
684   
685    if (asmr.currentKernel==ASMKERN_GLOBAL ||
686        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
687        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
688   
689    skipSpacesToEnd(linePtr, end);
690    const char* valuePlace = linePtr;
691    uint64_t value = BINGEN_NOTSUPPLIED;
692    const bool argIsOptional = ((1U<<target) & argIsOptionalMask)!=0;
693    bool good = getAbsoluteValueArg(asmr, value, linePtr, !argIsOptional);
694    /* ranges checking */
695    if (good)
696    {
697        switch(target)
698        {
699            case AMDCVAL_SGPRSNUM:
700            {
701                const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
702                            asmr.deviceType);
703                cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR,
704                                       REGCOUNT_NO_VCC);
705                if (value > maxSGPRsNum)
706                {
707                    char buf[64];
708                    snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
709                    ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
710                }
711                break;
712            }
713            case AMDCVAL_VGPRSNUM:
714            {
715                const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
716                            asmr.deviceType);
717                cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
718                if (value > maxVGPRsNum)
719                {
720                    char buf[64];
721                    snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
722                    ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
723                }
724                break;
725            }
726            case AMDCVAL_HWLOCAL:
727            {
728                const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
729                            asmr.deviceType);
730                const cxuint maxLocalSize = getGPUMaxLocalSize(arch);
731                if (value > maxLocalSize)
732                {
733                    char buf[64];
734                    snprintf(buf, 64, "HWLocalSize out of range (0-%u)", maxLocalSize);
735                    ASM_NOTGOOD_BY_ERROR(valuePlace, buf)
736                }
737                break;
738            }
739            case AMDCVAL_FLOATMODE:
740                asmr.printWarningForRange(8, value,
741                                  asmr.getSourcePos(valuePlace), WS_UNSIGNED);
742                value &= 0xff;
743                break;
744            case AMDCVAL_EXCEPTIONS:
745                asmr.printWarningForRange(7, value,
746                                  asmr.getSourcePos(valuePlace), WS_UNSIGNED);
747                value &= 0x7f;
748                break;
749            case AMDCVAL_UAVID:
750                if (value != BINGEN_NOTSUPPLIED && value >= 1024)
751                    ASM_NOTGOOD_BY_ERROR(valuePlace, "UAVId out of range (0-1023)")
752                break;
753            case AMDCVAL_CBID:
754                if (value != BINGEN_NOTSUPPLIED && value >= 1024)
755                    ASM_NOTGOOD_BY_ERROR(valuePlace, "ConstBufferId out of range (0-1023)")
756                break;
757            case AMDCVAL_PRINTFID:
758                if (value != BINGEN_NOTSUPPLIED && value >= 1024)
759                    ASM_NOTGOOD_BY_ERROR(valuePlace, "PrintfId out of range (0-1023)")
760                break;
761            case AMDCVAL_PRIVATEID:
762                if (value != BINGEN_NOTSUPPLIED && value >= 1024)
763                    ASM_NOTGOOD_BY_ERROR(valuePlace, "PrivateId out of range (0-1023)")
764                break;
765            case AMDCVAL_CONDOUT:
766            case AMDCVAL_EARLYEXIT:
767            case AMDCVAL_HWREGION:
768            case AMDCVAL_PGMRSRC2:
769                asmr.printWarningForRange(32, value,
770                                  asmr.getSourcePos(valuePlace), WS_UNSIGNED);
771                break;
772            default:
773                asmr.printWarningForRange(32, value, asmr.getSourcePos(valuePlace));
774                break;
775        }
776    }
777   
778    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
779        return;
780   
781    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
782    // set value
783    switch(target)
784    {
785        case AMDCVAL_SGPRSNUM:
786            config.usedSGPRsNum = value;
787            break;
788        case AMDCVAL_VGPRSNUM:
789            config.usedVGPRsNum = value;
790            break;
791        case AMDCVAL_PGMRSRC2:
792            config.pgmRSRC2 = value;
793            break;
794        case AMDCVAL_FLOATMODE:
795            config.floatMode = value;
796            break;
797        case AMDCVAL_HWLOCAL:
798            config.hwLocalSize = value;
799            break;
800        case AMDCVAL_HWREGION:
801            config.hwRegion = value;
802            break;
803        case AMDCVAL_PRIVATEID:
804            config.privateId = value;
805            break;
806        case AMDCVAL_SCRATCHBUFFER:
807            config.scratchBufferSize = value;
808            break;
809        case AMDCVAL_UAVPRIVATE:
810            config.uavPrivate = value;
811            break;
812        case AMDCVAL_UAVID:
813            config.uavId = value;
814            break;
815        case AMDCVAL_CBID:
816            config.constBufferId = value;
817            break;
818        case AMDCVAL_PRINTFID:
819            config.printfId = value;
820            break;
821        case AMDCVAL_EARLYEXIT:
822            config.earlyExit = value;
823            break;
824        case AMDCVAL_CONDOUT:
825            config.condOut = value;
826            break;
827        case AMDCVAL_EXCEPTIONS:
828            config.exceptions = value;
829            break;
830        default:
831            break;
832    }
833}
834
835void AsmAmdPseudoOps::setConfigBoolValue(AsmAmdHandler& handler, const char* pseudoOpPlace,
836                      const char* linePtr, AmdConfigValueTarget target)
837{
838    Assembler& asmr = handler.assembler;
839    const char* end = asmr.line + asmr.lineSize;
840   
841    if (asmr.currentKernel==ASMKERN_GLOBAL ||
842        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
843        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
844   
845    skipSpacesToEnd(linePtr, end);
846    if (!checkGarbagesAtEnd(asmr, linePtr))
847        return;
848   
849    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
850    if (target == AMDCVAL_USECONSTDATA)
851        config.useConstantData = true;
852    else if (target == AMDCVAL_USEPRINTF)
853        config.usePrintf = true;
854    else if (target == AMDCVAL_IEEEMODE)
855        config.ieeeMode = true;
856    else if (target == AMDCVAL_TGSIZE)
857        config.tgSize = true;
858}
859
860bool AsmAmdPseudoOps::parseCWS(Assembler& asmr, const char* pseudoOpPlace,
861              const char* linePtr, uint64_t* out)
862{
863    const char* end = asmr.line + asmr.lineSize;
864    skipSpacesToEnd(linePtr, end);
865    // default value is (1,1,1)
866    out[0] = 1;
867    out[1] = 1;
868    out[2] = 1;
869    const char* valuePlace1 = linePtr;
870    const char* valuePlace2 = nullptr;
871    const char* valuePlace3 = nullptr;
872    bool good = getAbsoluteValueArg(asmr, out[0], linePtr, false);
873    if (good)
874        asmr.printWarningForRange(32, out[0], asmr.getSourcePos(valuePlace1), WS_UNSIGNED);
875    bool haveComma;
876    if (!skipComma(asmr, haveComma, linePtr))
877        return false;
878    if (haveComma)
879    {
880        // second and third argument is optional
881        skipSpacesToEnd(linePtr, end);
882        valuePlace2 = linePtr;
883        if (getAbsoluteValueArg(asmr, out[1], linePtr, false))
884            asmr.printWarningForRange(32, out[1], asmr.getSourcePos(valuePlace2),
885                              WS_UNSIGNED);
886        else
887            good = false;
888       
889        if (!skipComma(asmr, haveComma, linePtr))
890            return false;
891        if (haveComma)
892        {
893            valuePlace3 = linePtr;
894            if (getAbsoluteValueArg(asmr, out[2], linePtr, false))
895                asmr.printWarningForRange(32, out[2], asmr.getSourcePos(valuePlace3),
896                            WS_UNSIGNED);
897            else
898                good = false;
899        }
900    }
901    if (out[0] != 0 || out[1]!=0 || out[2]!=0)
902    {
903        if (out[0] == 0)
904            ASM_NOTGOOD_BY_ERROR(valuePlace1, "Group size comment must be not zero");
905        if (out[1] == 0)
906            ASM_NOTGOOD_BY_ERROR(valuePlace2, "Group size comment must be not zero");
907        if (out[2] == 0)
908            ASM_NOTGOOD_BY_ERROR(valuePlace3, "Group size comment must be not zero");
909    }
910   
911    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
912        return false;
913    return true;
914}
915
916void AsmAmdPseudoOps::setCWS(AsmAmdHandler& handler, const char* pseudoOpPlace,
917                      const char* linePtr)
918{
919    Assembler& asmr = handler.assembler;
920    if (asmr.currentKernel==ASMKERN_GLOBAL ||
921        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
922        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
923   
924    uint64_t out[3] = { 1, 1, 1 };
925    if (!parseCWS(asmr, pseudoOpPlace, linePtr, out))
926        return;
927    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
928    config.reqdWorkGroupSize[0] = out[0];
929    config.reqdWorkGroupSize[1] = out[1];
930    config.reqdWorkGroupSize[2] = out[2];
931}
932
933/// data class names
934static const std::pair<const char*, cxuint> dataClassMap[] =
935{
936    { "imm_alu_bool32_const", 0x06 },
937    { "imm_alu_float_const", 0x05 },
938    { "imm_const_buffer", 0x02 },
939    { "imm_context_base", 0x1d },
940    { "imm_dispatch_id", 0x0c },
941    { "imm_gds_counter_range", 0x07 },
942    { "imm_gds_memory_range", 0x08 },
943    { "imm_generic_user_data", 0x20 },
944    { "imm_global_offset", 0x1f },
945    { "imm_gws_base", 0x09 },
946    { "imm_heap_buffer", 0x0e },
947    { "imm_kernel_arg", 0x0f },
948    { "imm_lds_esgs_size", 0x1e },
949    { "imm_resource", 0x00 },
950    { "imm_sampler", 0x01 },
951    { "imm_scratch_buffer", 0x0d },
952    { "imm_uav", 0x04 },
953    { "imm_vertex_buffer", 0x03 },
954    { "imm_work_group_range", 0x0b },
955    { "imm_work_item_range", 0x0a },
956    { "ptr_const_buffer_table", 0x14 },
957    { "ptr_extended_user_data", 0x19 },
958    { "ptr_indirect_internal_resource", 0x1b },
959    { "ptr_indirect_resource", 0x1a },
960    { "ptr_indirect_uav", 0x1c },
961    { "ptr_internal_global_table", 0x18 },
962    { "ptr_internal_resource_table", 0x12 },
963    { "ptr_resource_table", 0x11 },
964    { "ptr_sampler_table", 0x13 },
965    { "ptr_so_buffer_table", 0x16 },
966    { "ptr_uav_table", 0x17 },
967    { "ptr_vertex_buffer_table", 0x15 },
968    { "sub_ptr_fetch_shader", 0x10 }
969};
970
971static const size_t dataClassMapSize = sizeof(dataClassMap) /
972        sizeof(std::pair<const char*, uint32_t>);
973
974void AsmAmdPseudoOps::addUserData(AsmAmdHandler& handler, const char* pseudoOpPlace,
975                      const char* linePtr)
976{
977    Assembler& asmr = handler.assembler;
978    const char* end = asmr.line + asmr.lineSize;
979    if (asmr.currentKernel==ASMKERN_GLOBAL ||
980        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
981        PSEUDOOP_RETURN_BY_ERROR("Illegal place of UserData")
982   
983    cxuint dataClass = 0;
984    bool good = true;
985    // parse user data class
986    good &= getEnumeration(asmr, linePtr, "Data Class", dataClassMapSize,
987                    dataClassMap, dataClass);
988   
989    if (!skipRequiredComma(asmr, linePtr))
990        return;
991    skipSpacesToEnd(linePtr, end);
992    uint64_t apiSlot = 0;
993    const char* apiSlotPlace = linePtr;
994    // api slot (is 32-bit value)
995    if (getAbsoluteValueArg(asmr, apiSlot, linePtr, true))
996        asmr.printWarningForRange(32, apiSlot, asmr.getSourcePos(apiSlotPlace),
997                                  WS_UNSIGNED);
998    else
999        good = false;
1000   
1001    if (!skipRequiredComma(asmr, linePtr))
1002        return;
1003    skipSpacesToEnd(linePtr, end);
1004    uint64_t regStart = 0;
1005    const char* regStartPlace = linePtr;
1006    if (getAbsoluteValueArg(asmr, regStart, linePtr, true))
1007    {
1008        // must be in (0-15)
1009        if (regStart > 15)
1010            ASM_NOTGOOD_BY_ERROR(regStartPlace, "RegStart out of range (0-15)")
1011    }
1012    else
1013        good = false;
1014   
1015    if (!skipRequiredComma(asmr, linePtr))
1016        return;
1017    uint64_t regSize = 0;
1018    if (getAbsoluteValueArg(asmr, regSize, linePtr, true))
1019    {
1020        if (usumGt(regStart, regSize, 16U))
1021            ASM_NOTGOOD_BY_ERROR(regStartPlace, "RegStart+RegSize out of range (0-16)")
1022    }
1023    else
1024        good = false;
1025   
1026    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1027        return;
1028   
1029    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
1030    if (config.userDatas.size() == 16)
1031        PSEUDOOP_RETURN_BY_ERROR("Too many UserData elements")
1032    AmdUserData userData;
1033    userData.dataClass = dataClass;
1034    userData.apiSlot = apiSlot;
1035    userData.regStart = regStart;
1036    userData.regSize = regSize;
1037    config.userDatas.push_back(userData);
1038}
1039
1040void AsmAmdPseudoOps::setDimensions(AsmAmdHandler& handler, const char* pseudoOpPlace,
1041                      const char* linePtr)
1042{
1043    Assembler& asmr = handler.assembler;
1044    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1045        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1046        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1047    cxuint dimMask = 0;
1048    if (!parseDimensions(asmr, linePtr, dimMask))
1049        return;
1050    if (!checkGarbagesAtEnd(asmr, linePtr))
1051        return;
1052    handler.output.kernels[asmr.currentKernel].config.dimMask = dimMask;
1053}
1054
1055/* argument type map - value is cxuint for getEnumaration */
1056static const std::pair<const char*, cxuint> argTypeNameMap[] =
1057{
1058    { "char", cxuint(KernelArgType::CHAR) },
1059    { "char16", cxuint(KernelArgType::CHAR16) },
1060    { "char2", cxuint(KernelArgType::CHAR2) },
1061    { "char3", cxuint(KernelArgType::CHAR3) },
1062    { "char4", cxuint(KernelArgType::CHAR4) },
1063    { "char8", cxuint(KernelArgType::CHAR8) },
1064    { "clkevent", cxuint(KernelArgType::CLKEVENT) },
1065    { "counter32", cxuint(KernelArgType::COUNTER32) },
1066    { "counter64", cxuint(KernelArgType::COUNTER64) },
1067    { "double", cxuint(KernelArgType::DOUBLE) },
1068    { "double16", cxuint(KernelArgType::DOUBLE16) },
1069    { "double2", cxuint(KernelArgType::DOUBLE2) },
1070    { "double3", cxuint(KernelArgType::DOUBLE3) },
1071    { "double4", cxuint(KernelArgType::DOUBLE4) },
1072    { "double8", cxuint(KernelArgType::DOUBLE8) },
1073    { "float", cxuint(KernelArgType::FLOAT) },
1074    { "float16", cxuint(KernelArgType::FLOAT16) },
1075    { "float2", cxuint(KernelArgType::FLOAT2) },
1076    { "float3", cxuint(KernelArgType::FLOAT3) },
1077    { "float4", cxuint(KernelArgType::FLOAT4) },
1078    { "float8", cxuint(KernelArgType::FLOAT8) },
1079    { "image", cxuint(KernelArgType::IMAGE) },
1080    { "image1d", cxuint(KernelArgType::IMAGE1D) },
1081    { "image1d_array", cxuint(KernelArgType::IMAGE1D_ARRAY) },
1082    { "image1d_buffer", cxuint(KernelArgType::IMAGE1D_BUFFER) },
1083    { "image2d", cxuint(KernelArgType::IMAGE2D) },
1084    { "image2d_array", cxuint(KernelArgType::IMAGE2D_ARRAY) },
1085    { "image3d", cxuint(KernelArgType::IMAGE3D) },
1086    { "int", cxuint(KernelArgType::INT) },
1087    { "int16", cxuint(KernelArgType::INT16) },
1088    { "int2", cxuint(KernelArgType::INT2) },
1089    { "int3", cxuint(KernelArgType::INT3) },
1090    { "int4", cxuint(KernelArgType::INT4) },
1091    { "int8", cxuint(KernelArgType::INT8) },
1092    { "long", cxuint(KernelArgType::LONG) },
1093    { "long16", cxuint(KernelArgType::LONG16) },
1094    { "long2", cxuint(KernelArgType::LONG2) },
1095    { "long3", cxuint(KernelArgType::LONG3) },
1096    { "long4", cxuint(KernelArgType::LONG4) },
1097    { "long8", cxuint(KernelArgType::LONG8) },
1098    { "pipe", cxuint(KernelArgType::PIPE) },
1099    { "queue", cxuint(KernelArgType::CMDQUEUE) },
1100    { "sampler", cxuint(KernelArgType::SAMPLER) },
1101    { "short", cxuint(KernelArgType::SHORT) },
1102    { "short16", cxuint(KernelArgType::SHORT16) },
1103    { "short2", cxuint(KernelArgType::SHORT2) },
1104    { "short3", cxuint(KernelArgType::SHORT3) },
1105    { "short4", cxuint(KernelArgType::SHORT4) },
1106    { "short8", cxuint(KernelArgType::SHORT8) },
1107    { "structure", cxuint(KernelArgType::STRUCTURE) },
1108    { "uchar", cxuint(KernelArgType::UCHAR) },
1109    { "uchar16", cxuint(KernelArgType::UCHAR16) },
1110    { "uchar2", cxuint(KernelArgType::UCHAR2) },
1111    { "uchar3", cxuint(KernelArgType::UCHAR3) },
1112    { "uchar4", cxuint(KernelArgType::UCHAR4) },
1113    { "uchar8", cxuint(KernelArgType::UCHAR8) },
1114    { "uint", cxuint(KernelArgType::UINT) },
1115    { "uint16", cxuint(KernelArgType::UINT16) },
1116    { "uint2", cxuint(KernelArgType::UINT2) },
1117    { "uint3", cxuint(KernelArgType::UINT3) },
1118    { "uint4", cxuint(KernelArgType::UINT4) },
1119    { "uint8", cxuint(KernelArgType::UINT8) },
1120    { "ulong", cxuint(KernelArgType::ULONG)},
1121    { "ulong16", cxuint(KernelArgType::ULONG16) },
1122    { "ulong2", cxuint(KernelArgType::ULONG2) },
1123    { "ulong3", cxuint(KernelArgType::ULONG3) },
1124    { "ulong4", cxuint(KernelArgType::ULONG4) },
1125    { "ulong8", cxuint(KernelArgType::ULONG8) },
1126    { "ushort", cxuint(KernelArgType::USHORT) },
1127    { "ushort16", cxuint(KernelArgType::USHORT16) },
1128    { "ushort2", cxuint(KernelArgType::USHORT2) },
1129    { "ushort3", cxuint(KernelArgType::USHORT3) },
1130    { "ushort4", cxuint(KernelArgType::USHORT4) },
1131    { "ushort8", cxuint(KernelArgType::USHORT8) },
1132    { "void", cxuint(KernelArgType::VOID) }
1133};
1134
1135static const char* defaultArgTypeNames[] = 
1136{
1137    "void", "uchar", "char", "ushort", "short", "uint", "int",
1138    "ulong", "long", "float", "double", "pointer", "image2d_t",
1139    "image1d_t", "image1d_array_t", "image1d_buffer_t",
1140    "image2d_t", "image2d_array_t", "image3d_t",
1141    "uchar2", "uchar3", "uchar4", "uchar8", "uchar16",
1142    "char2", "char3", "char4", "char8", "char16",
1143    "ushort2", "ushort3", "ushort4", "ushort8", "ushort16",
1144    "short2", "short3", "short4", "short8", "short16",
1145    "uint2", "uint3", "uint4", "uint8", "uint16",
1146    "int2", "int3", "int4", "int8", "int16",
1147    "ulong2", "ulong3", "ulong4", "ulong8", "ulong16",
1148    "long2", "long3", "long4", "long8", "long16",
1149    "float2", "float3", "float4", "float8", "float16",
1150    "double2", "double3", "double4", "double8", "double16",
1151    "sampler_t", "structure", "counter32_t", "counter64_t",
1152    "pipe", "queue_t", "clk_event_t"
1153};
1154
1155static const size_t argTypeNameMapSize = sizeof(argTypeNameMap) /
1156        sizeof(std::pair<const char*, KernelArgType>);
1157
1158// main routine to parse argument
1159bool AsmAmdPseudoOps::parseArg(Assembler& asmr, const char* pseudoOpPlace,
1160          const char* linePtr, const std::unordered_set<CString>& argNamesSet,
1161          AmdKernelArgInput& argInput, bool cl20)
1162{
1163    CString argName;
1164    const char* end = asmr.line + asmr.lineSize;
1165    const char* argNamePlace = linePtr;
1166   
1167    bool good = getNameArg(asmr, argName, linePtr, "argument name", true);
1168    if (argNamesSet.find(argName) != argNamesSet.end())
1169        // if found kernel arg with this same name
1170        ASM_NOTGOOD_BY_ERROR(argNamePlace, (std::string("Kernel argument '")+
1171                    argName.c_str()+"' is already defined").c_str())
1172   
1173    if (!skipRequiredComma(asmr, linePtr))
1174        return false;
1175   
1176    skipSpacesToEnd(linePtr, end);
1177    bool typeNameDefined = false;
1178    std::string typeName;
1179    if (linePtr!=end && *linePtr=='"')
1180    {
1181        // if type name defined by user
1182        good &= asmr.parseString(typeName, linePtr);
1183        if (!skipRequiredComma(asmr, linePtr))
1184            return false;
1185        typeNameDefined = true;
1186    }
1187   
1188    bool pointer = false;
1189    KernelArgType argType = KernelArgType::VOID;
1190    char name[20];
1191    skipSpacesToEnd(linePtr, end);
1192    const char* argTypePlace = linePtr;
1193    cxuint argTypeValue;
1194    if (getEnumeration(asmr, linePtr, "argument type", argTypeNameMapSize, argTypeNameMap,
1195                    argTypeValue))
1196    {
1197        argType = KernelArgType(argTypeValue);
1198        if (cl20 || argType <= KernelArgType::MAX_VALUE)
1199        {
1200            skipSpacesToEnd(linePtr, end);
1201            if (linePtr!=end && *linePtr == '*')
1202            {
1203                pointer = true; // if is pointer
1204                linePtr++;
1205            }
1206        }
1207        else
1208        {
1209            // if not OpenCL 2.0 and argument type only present in OpenCL 2.0
1210            skipSpacesToEnd(linePtr, end);
1211            ASM_NOTGOOD_BY_ERROR(linePtr, "Unknown argument type")
1212        }
1213    }
1214    else // if failed
1215        good = false;
1216   
1217    if (!pointer && argType == KernelArgType::COUNTER64)
1218        ASM_NOTGOOD_BY_ERROR(argTypePlace, "Unsupported counter64 type")
1219    if (pointer && (isKernelArgImage(argType) ||
1220            argType == KernelArgType::SAMPLER || argType == KernelArgType::POINTER ||
1221            argType == KernelArgType::COUNTER32 || argType == KernelArgType::COUNTER64))
1222        ASM_NOTGOOD_BY_ERROR(argTypePlace, "Illegal pointer type")
1223   
1224    if (!typeNameDefined)
1225    {
1226        // if type name is not supplied
1227        typeName = defaultArgTypeNames[cxuint(argType)];
1228        if (pointer)
1229            typeName.push_back('*');
1230    }
1231   
1232    KernelPtrSpace ptrSpace = KernelPtrSpace::NONE;
1233    cxbyte ptrAccess = 0;
1234    uint64_t structSizeVal = 0;
1235    uint64_t constSpaceSizeVal = 0;
1236    uint64_t resIdVal = BINGEN_DEFAULT;
1237    cxbyte usedArg = (cl20) ? 3 : 1;
1238   
1239    bool haveComma;
1240    bool haveLastArgument = false;
1241    if (pointer)
1242    {
1243        // if type is pointer
1244        if (argType == KernelArgType::STRUCTURE)
1245        {
1246            if (!skipRequiredComma(asmr, linePtr))
1247                return false;
1248            skipSpacesToEnd(linePtr, end);
1249            // parse extra structure size
1250            const char* structSizePlace = linePtr;
1251            if (getAbsoluteValueArg(asmr, structSizeVal, linePtr, true))
1252                asmr.printWarningForRange(sizeof(cxuint)<<3, structSizeVal,
1253                                  asmr.getSourcePos(structSizePlace), WS_UNSIGNED);
1254            else
1255                good = false;
1256        }
1257       
1258        if (!skipRequiredComma(asmr, linePtr))
1259            return false;
1260        skipSpacesToEnd(linePtr, end);
1261        const char* ptrSpacePlace = linePtr;
1262        // parse ptrSpace
1263        if (getNameArg(asmr, 10, name, linePtr, "pointer space", true))
1264        {
1265            toLowerString(name);
1266            if (::strcmp(name, "local")==0)
1267                ptrSpace = KernelPtrSpace::LOCAL;
1268            else if (::strcmp(name, "global")==0)
1269                ptrSpace = KernelPtrSpace::GLOBAL;
1270            else if (::strcmp(name, "constant")==0)
1271                ptrSpace = KernelPtrSpace::CONSTANT;
1272            else // not known or not given
1273                ASM_NOTGOOD_BY_ERROR(ptrSpacePlace, "Unknown pointer space")
1274        }
1275        else
1276            good = false;
1277       
1278        if (!skipComma(asmr, haveComma, linePtr))
1279            return false;
1280        if (haveComma)
1281        {
1282            // parse ptr access
1283            while (linePtr!=end && *linePtr!=',')
1284            {
1285                skipSpacesToEnd(linePtr, end);
1286                if (linePtr==end || *linePtr==',')
1287                    break;
1288                const char* ptrAccessPlace = linePtr;
1289                // parse acces qualifier (const,restrict,volatile)
1290                if (getNameArg(asmr, 10, name, linePtr, "access qualifier", true))
1291                {
1292                    if (::strcasecmp(name, "const")==0)
1293                        ptrAccess |= KARG_PTR_CONST;
1294                    else if (::strcasecmp(name, "restrict")==0)
1295                        ptrAccess |= KARG_PTR_RESTRICT;
1296                    else if (::strcasecmp(name, "volatile")==0)
1297                        ptrAccess |= KARG_PTR_VOLATILE;
1298                    else
1299                        ASM_NOTGOOD_BY_ERROR(ptrAccessPlace, "Unknown access qualifier")
1300                }
1301                else
1302                    good = false;
1303            }
1304           
1305            bool havePrevArgument = false;
1306            const char* place;
1307            if (ptrSpace == KernelPtrSpace::CONSTANT && !cl20)
1308            {
1309                /* parse constant space size for constant pointer */
1310                if (!skipComma(asmr, haveComma, linePtr))
1311                    return false;
1312                if (haveComma)
1313                {
1314                    skipSpacesToEnd(linePtr, end);
1315                    const char* place = linePtr;
1316                    if (getAbsoluteValueArg(asmr, constSpaceSizeVal, linePtr, false))
1317                        asmr.printWarningForRange(sizeof(cxuint)<<3, constSpaceSizeVal,
1318                                          asmr.getSourcePos(place), WS_UNSIGNED);
1319                    else
1320                        good = false;
1321                    havePrevArgument = true;
1322                }
1323            }
1324            else
1325                havePrevArgument = true;
1326           
1327            if (havePrevArgument && ptrSpace != KernelPtrSpace::LOCAL && !cl20)
1328            {
1329                /* global and constant have resource id (uavId) */
1330                if (!skipComma(asmr, haveComma, linePtr))
1331                    return false;
1332                if (haveComma)
1333                {
1334                    haveLastArgument = true;
1335                    skipSpacesToEnd(linePtr, end);
1336                    place = linePtr;
1337                    if (getAbsoluteValueArg(asmr, resIdVal, linePtr, false))
1338                    {
1339                        // for constant buffers, uavid is in range (0-159)
1340                        const cxuint maxUavId = (ptrSpace==KernelPtrSpace::CONSTANT) ?
1341                                159 : 1023;
1342                       
1343                        if (resIdVal != BINGEN_DEFAULT && resIdVal > maxUavId)
1344                        {
1345                            char buf[80];
1346                            snprintf(buf, 80, "UAVId out of range (0-%u)", maxUavId);
1347                            ASM_NOTGOOD_BY_ERROR(place, buf)
1348                        }
1349                    }
1350                    else
1351                        good = false;
1352                }
1353            }
1354            else
1355                haveLastArgument = havePrevArgument;
1356        }
1357    }
1358    else if (!pointer && isKernelArgImage(argType))
1359    {
1360        // if image type
1361        ptrSpace = KernelPtrSpace::GLOBAL;
1362        ptrAccess = KARG_PTR_READ_ONLY;
1363        if (!skipComma(asmr, haveComma, linePtr))
1364            return false;
1365        if (haveComma)
1366        {
1367            skipSpacesToEnd(linePtr, end);
1368            const char* ptrAccessPlace = linePtr;
1369            // access qualifier for image (rdonly,wronly)
1370            if (getNameArg(asmr, 15, name, linePtr, "access qualifier", false))
1371            {
1372                if (::strcmp(name, "read_only")==0 || ::strcmp(name, "rdonly")==0)
1373                    ptrAccess = KARG_PTR_READ_ONLY;
1374                else if (::strcmp(name, "write_only")==0 || ::strcmp(name, "wronly")==0)
1375                    ptrAccess = KARG_PTR_WRITE_ONLY;
1376                else if (*name!=0) // unknown
1377                    ASM_NOTGOOD_BY_ERROR(ptrAccessPlace, "Unknown access qualifier")
1378            }
1379            else
1380                good = false;
1381           
1382            if (!skipComma(asmr, haveComma, linePtr))
1383                return false;
1384            if (haveComma)
1385            {
1386                haveLastArgument = true;
1387                skipSpacesToEnd(linePtr, end);
1388                const char* place = linePtr;
1389                // resid for image (0-7 for write-only images, 0-127 for read-only images)
1390                if (getAbsoluteValueArg(asmr, resIdVal, linePtr, false))
1391                {
1392                    cxuint maxResId = (ptrAccess == KARG_PTR_READ_ONLY) ? 127 : 7;
1393                    if (resIdVal!=BINGEN_DEFAULT && resIdVal > maxResId)
1394                    {
1395                        char buf[80];
1396                        snprintf(buf, 80, "Resource Id out of range (0-%u)", maxResId);
1397                        ASM_NOTGOOD_BY_ERROR(place, buf)
1398                    }
1399                }
1400                else
1401                    good = false;
1402            }
1403        }
1404    }
1405    else if (!pointer && ((!cl20 && argType == KernelArgType::COUNTER32) ||
1406            (cl20 && argType == KernelArgType::SAMPLER)))
1407    {
1408        // counter uavId
1409        if (!skipComma(asmr, haveComma, linePtr))
1410            return false;
1411        if (haveComma)
1412        {
1413            haveLastArgument = true;
1414            skipSpacesToEnd(linePtr, end);
1415            const char* place = linePtr;
1416            if (getAbsoluteValueArg(asmr, resIdVal, linePtr, true))
1417            {
1418                // for OpenCL 1.2 is - resid in 0-7
1419                if (resIdVal!=BINGEN_DEFAULT && (!cl20 && resIdVal > 7))
1420                    ASM_NOTGOOD_BY_ERROR(place, "Resource Id out of range (0-7)")
1421                    // for OpenCL 1.2 is - resid in 0-15
1422                else if (resIdVal!=BINGEN_DEFAULT && cl20 && resIdVal > 15)
1423                    ASM_NOTGOOD_BY_ERROR(place, "Sampler Id out of range (0-15)")
1424            }
1425            else
1426                good = false;
1427        }
1428    }
1429    else if (!pointer && argType == KernelArgType::STRUCTURE)
1430    {
1431        /* parse structure size */
1432        if (!skipRequiredComma(asmr, linePtr))
1433            return false;
1434        skipSpacesToEnd(linePtr, end);
1435        const char* structSizePlace = linePtr;
1436        if (getAbsoluteValueArg(asmr, structSizeVal, linePtr, true))
1437            asmr.printWarningForRange(sizeof(cxuint)<<3, structSizeVal,
1438                              asmr.getSourcePos(structSizePlace), WS_UNSIGNED);
1439        else
1440            good = false;
1441        haveLastArgument = true;
1442    }
1443    else
1444        haveLastArgument = true;
1445   
1446    /* last argument is 'used' - indicate whether argument is used by kernel */
1447    if (haveLastArgument)
1448    {
1449        if (!skipComma(asmr, haveComma, linePtr))
1450            return false;
1451        if (haveComma)
1452        {
1453            skipSpacesToEnd(linePtr, end);
1454            const char* place = linePtr;
1455            good &= getNameArg(asmr, 10, name, linePtr, "unused specifier");
1456            toLowerString(name);
1457            if (::strcmp(name, "unused")==0)
1458                usedArg = false;
1459            else if (cl20 && ::strcmp(name, "rdonly")==0)
1460                usedArg = 1;
1461            else if (cl20 && ::strcmp(name, "wronly")==0)
1462                usedArg = 2;
1463            else
1464                ASM_NOTGOOD_BY_ERROR(place, "This is not 'unused' specifier")
1465        }
1466    }
1467   
1468    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1469        return false;
1470   
1471    argInput = { argName, typeName, (pointer) ? KernelArgType::POINTER :  argType,
1472        (pointer) ? argType : KernelArgType::VOID, ptrSpace, ptrAccess,
1473        cxuint(structSizeVal), size_t(constSpaceSizeVal), uint32_t(resIdVal), usedArg };
1474    return true;
1475}
1476
1477void AsmAmdPseudoOps::doArg(AsmAmdHandler& handler, const char* pseudoOpPlace,
1478                      const char* linePtr)
1479{
1480    Assembler& asmr = handler.assembler;
1481    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1482        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1483        PSEUDOOP_RETURN_BY_ERROR("Illegal place of kernel argument")
1484   
1485    auto& kernelState = *handler.kernelStates[asmr.currentKernel];
1486    AmdKernelArgInput argInput;
1487    if (!parseArg(asmr, pseudoOpPlace, linePtr, kernelState.argNamesSet, argInput, false))
1488        return;
1489    /* setup argument */
1490    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
1491    const CString argName = argInput.argName;
1492    config.args.push_back(std::move(argInput));
1493    /// put argName
1494    kernelState.argNamesSet.insert(argName);
1495}
1496
1497}
1498
1499bool AsmAmdHandler::parsePseudoOp(const CString& firstName,
1500       const char* stmtPlace, const char* linePtr)
1501{
1502    const size_t pseudoOp = binaryFind(amdPseudoOpNamesTbl, amdPseudoOpNamesTbl +
1503                    sizeof(amdPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
1504                   CStringLess()) - amdPseudoOpNamesTbl;
1505   
1506    switch(pseudoOp)
1507    {
1508        case AMDOP_ARG:
1509            AsmAmdPseudoOps::doArg(*this, stmtPlace, linePtr);
1510            break;
1511        case AMDOP_BOOLCONSTS:
1512            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1513                            CALNOTE_ATI_BOOL32CONSTS);
1514            break;
1515        case AMDOP_CALNOTE:
1516            AsmAmdPseudoOps::addCustomCALNote(*this, stmtPlace, linePtr);
1517            break;
1518        case AMDOP_CBID:
1519            AsmAmdPseudoOps::doCBId(*this, stmtPlace, linePtr);
1520            break;
1521        case AMDOP_CBMASK:
1522            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1523                         1U<<CALNOTE_ATI_CONSTANT_BUFFERS, "cbmask");
1524            break;
1525        case AMDOP_COMPILE_OPTIONS:
1526            AsmAmdPseudoOps::setCompileOptions(*this, linePtr);
1527            break;
1528        case AMDOP_CONDOUT:
1529            AsmAmdPseudoOps::doCondOut(*this, stmtPlace, linePtr);
1530            break;
1531        case AMDOP_CONFIG:
1532            AsmAmdPseudoOps::doConfig(*this, stmtPlace, linePtr);
1533            break;
1534        case AMDOP_CONSTANTBUFFERS:
1535            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1536                            CALNOTE_ATI_CONSTANT_BUFFERS);
1537            break;
1538        case AMDOP_CWS:
1539        case AMDOP_REQD_WORK_GROUP_SIZE:
1540            AsmAmdPseudoOps::setCWS(*this, stmtPlace, linePtr);
1541            break;
1542        case AMDOP_DIMS:
1543            AsmAmdPseudoOps::setDimensions(*this, stmtPlace, linePtr);
1544            break;
1545        case AMDOP_DRIVER_INFO:
1546            AsmAmdPseudoOps::setDriverInfo(*this, linePtr);
1547            break;
1548        case AMDOP_DRIVER_VERSION:
1549            AsmAmdPseudoOps::setDriverVersion(*this, linePtr);
1550            break;
1551        case AMDOP_EARLYEXIT:
1552            AsmAmdPseudoOps::doEarlyExit(*this, stmtPlace, linePtr);
1553            break;
1554        case AMDOP_ENTRY:
1555            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1556                         (1U<<CALNOTE_ATI_PROGINFO) | (1<<CALNOTE_ATI_UAV), "entry");
1557            break;
1558        case AMDOP_EXCEPTIONS:
1559            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_EXCEPTIONS);
1560            break;
1561        case AMDOP_FLOATCONSTS:
1562            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1563                            CALNOTE_ATI_FLOAT32CONSTS);
1564            break;
1565        case AMDOP_FLOATMODE:
1566            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_FLOATMODE);
1567            break;
1568        case AMDOP_GETDRVVER:
1569            AsmAmdPseudoOps::getDriverVersion(*this, linePtr);
1570            break;
1571        case AMDOP_GLOBALBUFFERS:
1572            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1573                            CALNOTE_ATI_GLOBAL_BUFFERS);
1574            break;
1575        case AMDOP_GLOBALDATA:
1576            AsmAmdPseudoOps::doGlobalData(*this, stmtPlace, linePtr);
1577            break;
1578        case AMDOP_HEADER:
1579            AsmAmdPseudoOps::addHeader(*this, stmtPlace, linePtr);
1580            break;
1581        case AMDOP_HWLOCAL:
1582        case AMDOP_LOCALSIZE:
1583            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_HWLOCAL);
1584            break;
1585        case AMDOP_HWREGION:
1586            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_HWREGION);
1587            break;
1588        case AMDOP_IEEEMODE:
1589            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1590                                AMDCVAL_IEEEMODE);
1591            break;
1592        case AMDOP_INPUTS:
1593            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1594                            CALNOTE_ATI_INPUTS);
1595            break;
1596        case AMDOP_INPUTSAMPLERS:
1597            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1598                            CALNOTE_ATI_INPUT_SAMPLERS);
1599            break;
1600        case AMDOP_INTCONSTS:
1601            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1602                            CALNOTE_ATI_INT32CONSTS);
1603            break;
1604        case AMDOP_METADATA:
1605            AsmAmdPseudoOps::addMetadata(*this, stmtPlace, linePtr);
1606            break;
1607        case AMDOP_OUTPUTS:
1608            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1609                            CALNOTE_ATI_OUTPUTS);
1610            break;
1611        case AMDOP_PERSISTENTBUFFERS:
1612            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1613                            CALNOTE_ATI_PERSISTENT_BUFFERS);
1614            break;
1615        case AMDOP_PGMRSRC2:
1616            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PGMRSRC2);
1617            break;
1618        case AMDOP_PRINTFID:
1619            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PRINTFID);
1620            break;
1621        case AMDOP_PRIVATEID:
1622            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PRIVATEID);
1623            break;
1624        case AMDOP_PROGINFO:
1625            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1626                            CALNOTE_ATI_PROGINFO);
1627            break;
1628        case AMDOP_SAMPLER:
1629            AsmAmdPseudoOps::doSampler(*this, stmtPlace, linePtr);
1630            break;
1631        case AMDOP_SCRATCHBUFFER:
1632            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1633                                AMDCVAL_SCRATCHBUFFER);
1634            break;
1635        case AMDOP_SCRATCHBUFFERS:
1636            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1637                            CALNOTE_ATI_SCRATCH_BUFFERS);
1638            break;
1639        case AMDOP_SEGMENT:
1640            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1641                    (1U<<CALNOTE_ATI_INT32CONSTS) | (1U<<CALNOTE_ATI_FLOAT32CONSTS) |
1642                    (1U<<CALNOTE_ATI_BOOL32CONSTS), "segment");
1643            break;
1644        case AMDOP_SGPRSNUM:
1645            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_SGPRSNUM);
1646            break;
1647        case AMDOP_SUBCONSTANTBUFFERS:
1648            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1649                            CALNOTE_ATI_SUB_CONSTANT_BUFFERS);
1650            break;
1651        case AMDOP_TGSIZE:
1652            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1653                            AMDCVAL_TGSIZE);
1654            break;
1655        case AMDOP_UAV:
1656            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1657                            CALNOTE_ATI_UAV);
1658            break;
1659        case AMDOP_UAVID:
1660            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_UAVID);
1661            break;
1662        case AMDOP_UAVMAILBOXSIZE:
1663            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1664                            CALNOTE_ATI_UAV_MAILBOX_SIZE);
1665            break;
1666        case AMDOP_UAVOPMASK:
1667            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1668                            CALNOTE_ATI_UAV_OP_MASK);
1669            break;
1670        case AMDOP_UAVPRIVATE:
1671            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_UAVPRIVATE);
1672            break;
1673        case AMDOP_USECONSTDATA:
1674            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1675                            AMDCVAL_USECONSTDATA);
1676            break;
1677        case AMDOP_USEPRINTF:
1678            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1679                            AMDCVAL_USEPRINTF);
1680            break;
1681        case AMDOP_USERDATA:
1682            AsmAmdPseudoOps::addUserData(*this, stmtPlace, linePtr);
1683            break;
1684        case AMDOP_VGPRSNUM:
1685            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_VGPRSNUM);
1686            break;
1687        default:
1688            return false;
1689    }
1690    return true;
1691}
1692
1693bool AsmAmdHandler::prepareBinary()
1694{
1695    if (assembler.isaAssembler!=nullptr)
1696        saveCurrentAllocRegs(); // save last kernel allocated registers to kernel state
1697   
1698    output.is64Bit = assembler.is64Bit();
1699    output.deviceType = assembler.getDeviceType();
1700    /* initialize sections */
1701    const size_t sectionsNum = sections.size();
1702    const size_t kernelsNum = kernelStates.size();
1703   
1704    // set sections as outputs
1705    for (size_t i = 0; i < sectionsNum; i++)
1706    {
1707        const AsmSection& asmSection = assembler.sections[i];
1708        const Section& section = sections[i];
1709        const size_t sectionSize = asmSection.getSize();
1710        const cxbyte* sectionData = (!asmSection.content.empty()) ?
1711                asmSection.content.data() : (const cxbyte*)"";
1712        AmdKernelInput* kernel = (section.kernelId!=ASMKERN_GLOBAL) ?
1713                    &output.kernels[section.kernelId] : nullptr;
1714               
1715        switch(asmSection.type)
1716        {
1717            case AsmSectionType::CODE:
1718                kernel->codeSize = sectionSize;
1719                kernel->code = sectionData;
1720                break;
1721            case AsmSectionType::AMD_HEADER:
1722                kernel->headerSize = sectionSize;
1723                kernel->header = sectionData;
1724                break;
1725            case AsmSectionType::AMD_METADATA:
1726                kernel->metadataSize = sectionSize;
1727                kernel->metadata = (const char*)sectionData;
1728                break;
1729            case AsmSectionType::DATA:
1730                if (section.kernelId == ASMKERN_GLOBAL)
1731                {
1732                    // this is global data
1733                    if (sectionSize!=0)
1734                    {
1735                        output.globalDataSize = sectionSize;
1736                        output.globalData = sectionData;
1737                    }
1738                }
1739                else
1740                {
1741                    // this is kernel data
1742                    kernel->dataSize = sectionSize;
1743                    kernel->data = sectionData;
1744                }
1745                break;
1746            case AsmSectionType::AMD_CALNOTE:
1747            {
1748                // add new CAL note to output
1749                CALNoteInput calNote;
1750                calNote.header.type = section.extraId;
1751                calNote.header.descSize = sectionSize;
1752                calNote.header.nameSize = 8;
1753                ::memcpy(calNote.header.name, "ATI CAL", 8);
1754                calNote.data = sectionData;
1755                kernel->calNotes.push_back(calNote);
1756                break;
1757            }
1758            case AsmSectionType::EXTRA_PROGBITS:
1759            case AsmSectionType::EXTRA_NOTE:
1760            case AsmSectionType::EXTRA_NOBITS:
1761            case AsmSectionType::EXTRA_SECTION:
1762            {
1763                // handle extra (user) section, set section type and its flags
1764                uint32_t elfSectType =
1765                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
1766                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
1767                             SHT_PROGBITS;
1768                uint32_t elfSectFlags = 
1769                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
1770                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
1771                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
1772                // put extra sections to binary
1773                if (section.kernelId == ASMKERN_GLOBAL)
1774                    output.extraSections.push_back({section.name, sectionSize, sectionData,
1775                            asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1776                            elfSectFlags, ELFSECTID_NULL, 0, 0 });
1777                else // to inner binary
1778                    kernel->extraSections.push_back({section.name, sectionSize, sectionData,
1779                            asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1780                            elfSectFlags, ELFSECTID_NULL, 0, 0 });
1781                break;
1782            }
1783            default: // ignore other sections
1784                break;
1785        }
1786    }
1787   
1788    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
1789    // determine max SGPRs number for architecture excluding VCC
1790    const cxuint maxSGPRsNumWithoutVCC = getGPUMaxRegistersNum(arch, REGTYPE_SGPR,
1791                REGCOUNT_NO_VCC);
1792    // set up number of the allocated SGPRs and VGPRs for kernel
1793    for (size_t i = 0; i < kernelsNum; i++)
1794    {
1795        if (!output.kernels[i].useConfig)
1796            continue;
1797        AmdKernelConfig& config = output.kernels[i].config;
1798        cxuint userSGPRsNum = 0;
1799        /* include userData sgprs */
1800        for (cxuint i = 0; i < config.userDatas.size(); i++)
1801            userSGPRsNum = std::max(userSGPRsNum,
1802                        config.userDatas[i].regStart+config.userDatas[i].regSize);
1803       
1804        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
1805                ((config.pgmRSRC2>>7)&7);
1806        cxuint minRegsNum[2];
1807        // get minimum required register by user data
1808        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
1809                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
1810                   ((config.scratchBufferSize!=0) ? GPUSETUP_SCRATCH_EN : 0), minRegsNum);
1811        // set used SGPRs number if not specified by user
1812        if (config.usedSGPRsNum==BINGEN_DEFAULT)
1813            config.usedSGPRsNum = std::min(maxSGPRsNumWithoutVCC,
1814                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]));
1815        if (config.usedVGPRsNum==BINGEN_DEFAULT)
1816            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
1817    }
1818   
1819    /* put extra symbols */
1820    if (assembler.flags & ASM_FORCE_ADD_SYMBOLS)
1821        for (const AsmSymbolEntry& symEntry: assembler.globalScope.symbolMap)
1822        {
1823            if (!symEntry.second.hasValue ||
1824                ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
1825                continue; // unresolved or local
1826            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
1827                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
1828            if (binSectId==ELFSECTID_UNDEF)
1829                continue; // no section
1830           
1831            const BinSymbol binSym = { symEntry.first, symEntry.second.value,
1832                        symEntry.second.size, binSectId, false, symEntry.second.info,
1833                        symEntry.second.other };
1834           
1835            if (symEntry.second.sectionId == ASMSECT_ABS ||
1836                sections[symEntry.second.sectionId].kernelId == ASMKERN_GLOBAL)
1837                output.extraSymbols.push_back(std::move(binSym));
1838            else // to kernel extra symbols
1839                output.kernels[sections[symEntry.second.sectionId].kernelId].extraSymbols
1840                            .push_back(std::move(binSym));
1841        }
1842    // driver version setup
1843    if (output.driverVersion==0 && output.driverInfo.empty() &&
1844        (assembler.flags&ASM_TESTRUN)==0)
1845    {
1846        if (assembler.driverVersion==0) // just detect driver version
1847            output.driverVersion = detectedDriverVersion;
1848        else // from assembler setup
1849            output.driverVersion = assembler.driverVersion;
1850    }
1851    return true;
1852}
1853
1854void AsmAmdHandler::writeBinary(std::ostream& os) const
1855{
1856    AmdGPUBinGenerator binGenerator(&output);
1857    binGenerator.generate(os);
1858}
1859
1860void AsmAmdHandler::writeBinary(Array<cxbyte>& array) const
1861{
1862    AmdGPUBinGenerator binGenerator(&output);
1863    binGenerator.generate(array);
1864}
Note: See TracBrowser for help on using the repository browser.