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

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

CLRadeonExtender: Asm: CWS and friends accepts 0,0,0 value.

File size: 71.1 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, true);
873    if (good)
874    {
875        asmr.printWarningForRange(32, out[0], asmr.getSourcePos(valuePlace1), WS_UNSIGNED);
876    }
877    bool haveComma;
878    if (!skipComma(asmr, haveComma, linePtr))
879        return false;
880    if (haveComma)
881    {
882        // second and third argument is optional
883        skipSpacesToEnd(linePtr, end);
884        valuePlace2 = linePtr;
885        if (getAbsoluteValueArg(asmr, out[1], linePtr, false))
886        {
887            asmr.printWarningForRange(32, out[1], asmr.getSourcePos(valuePlace2),
888                              WS_UNSIGNED);
889        }
890        else
891            good = false;
892       
893        if (!skipComma(asmr, haveComma, linePtr))
894            return false;
895        if (haveComma)
896        {
897            valuePlace3 = linePtr;
898            if (getAbsoluteValueArg(asmr, out[2], linePtr, false))
899            {
900                asmr.printWarningForRange(32, out[2], asmr.getSourcePos(valuePlace3),
901                            WS_UNSIGNED);
902            }
903            else
904                good = false;
905        }
906    }
907    if (out[0] != 0 || out[1]!=0 || out[2]!=0)
908    {
909        if (out[0] == 0)
910            ASM_NOTGOOD_BY_ERROR(valuePlace1, "Group size comment must be not zero");
911        if (out[1] == 0)
912            ASM_NOTGOOD_BY_ERROR(valuePlace2, "Group size comment must be not zero");
913        if (out[2] == 0)
914            ASM_NOTGOOD_BY_ERROR(valuePlace3, "Group size comment must be not zero");
915    }
916   
917    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
918        return false;
919    return true;
920}
921
922void AsmAmdPseudoOps::setCWS(AsmAmdHandler& handler, const char* pseudoOpPlace,
923                      const char* linePtr)
924{
925    Assembler& asmr = handler.assembler;
926    if (asmr.currentKernel==ASMKERN_GLOBAL ||
927        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
928        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
929   
930    uint64_t out[3] = { 1, 1, 1 };
931    if (!parseCWS(asmr, pseudoOpPlace, linePtr, out))
932        return;
933    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
934    config.reqdWorkGroupSize[0] = out[0];
935    config.reqdWorkGroupSize[1] = out[1];
936    config.reqdWorkGroupSize[2] = out[2];
937}
938
939/// data class names
940static const std::pair<const char*, cxuint> dataClassMap[] =
941{
942    { "imm_alu_bool32_const", 0x06 },
943    { "imm_alu_float_const", 0x05 },
944    { "imm_const_buffer", 0x02 },
945    { "imm_context_base", 0x1d },
946    { "imm_dispatch_id", 0x0c },
947    { "imm_gds_counter_range", 0x07 },
948    { "imm_gds_memory_range", 0x08 },
949    { "imm_generic_user_data", 0x20 },
950    { "imm_global_offset", 0x1f },
951    { "imm_gws_base", 0x09 },
952    { "imm_heap_buffer", 0x0e },
953    { "imm_kernel_arg", 0x0f },
954    { "imm_lds_esgs_size", 0x1e },
955    { "imm_resource", 0x00 },
956    { "imm_sampler", 0x01 },
957    { "imm_scratch_buffer", 0x0d },
958    { "imm_uav", 0x04 },
959    { "imm_vertex_buffer", 0x03 },
960    { "imm_work_group_range", 0x0b },
961    { "imm_work_item_range", 0x0a },
962    { "ptr_const_buffer_table", 0x14 },
963    { "ptr_extended_user_data", 0x19 },
964    { "ptr_indirect_internal_resource", 0x1b },
965    { "ptr_indirect_resource", 0x1a },
966    { "ptr_indirect_uav", 0x1c },
967    { "ptr_internal_global_table", 0x18 },
968    { "ptr_internal_resource_table", 0x12 },
969    { "ptr_resource_table", 0x11 },
970    { "ptr_sampler_table", 0x13 },
971    { "ptr_so_buffer_table", 0x16 },
972    { "ptr_uav_table", 0x17 },
973    { "ptr_vertex_buffer_table", 0x15 },
974    { "sub_ptr_fetch_shader", 0x10 }
975};
976
977static const size_t dataClassMapSize = sizeof(dataClassMap) /
978        sizeof(std::pair<const char*, uint32_t>);
979
980void AsmAmdPseudoOps::addUserData(AsmAmdHandler& handler, const char* pseudoOpPlace,
981                      const char* linePtr)
982{
983    Assembler& asmr = handler.assembler;
984    const char* end = asmr.line + asmr.lineSize;
985    if (asmr.currentKernel==ASMKERN_GLOBAL ||
986        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
987        PSEUDOOP_RETURN_BY_ERROR("Illegal place of UserData")
988   
989    cxuint dataClass = 0;
990    bool good = true;
991    // parse user data class
992    good &= getEnumeration(asmr, linePtr, "Data Class", dataClassMapSize,
993                    dataClassMap, dataClass);
994   
995    if (!skipRequiredComma(asmr, linePtr))
996        return;
997    skipSpacesToEnd(linePtr, end);
998    uint64_t apiSlot = 0;
999    const char* apiSlotPlace = linePtr;
1000    // api slot (is 32-bit value)
1001    if (getAbsoluteValueArg(asmr, apiSlot, linePtr, true))
1002        asmr.printWarningForRange(32, apiSlot, asmr.getSourcePos(apiSlotPlace),
1003                                  WS_UNSIGNED);
1004    else
1005        good = false;
1006   
1007    if (!skipRequiredComma(asmr, linePtr))
1008        return;
1009    skipSpacesToEnd(linePtr, end);
1010    uint64_t regStart = 0;
1011    const char* regStartPlace = linePtr;
1012    if (getAbsoluteValueArg(asmr, regStart, linePtr, true))
1013    {
1014        // must be in (0-15)
1015        if (regStart > 15)
1016            ASM_NOTGOOD_BY_ERROR(regStartPlace, "RegStart out of range (0-15)")
1017    }
1018    else
1019        good = false;
1020   
1021    if (!skipRequiredComma(asmr, linePtr))
1022        return;
1023    uint64_t regSize = 0;
1024    if (getAbsoluteValueArg(asmr, regSize, linePtr, true))
1025    {
1026        if (usumGt(regStart, regSize, 16U))
1027            ASM_NOTGOOD_BY_ERROR(regStartPlace, "RegStart+RegSize out of range (0-16)")
1028    }
1029    else
1030        good = false;
1031   
1032    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1033        return;
1034   
1035    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
1036    if (config.userDatas.size() == 16)
1037        PSEUDOOP_RETURN_BY_ERROR("Too many UserData elements")
1038    AmdUserData userData;
1039    userData.dataClass = dataClass;
1040    userData.apiSlot = apiSlot;
1041    userData.regStart = regStart;
1042    userData.regSize = regSize;
1043    config.userDatas.push_back(userData);
1044}
1045
1046void AsmAmdPseudoOps::setDimensions(AsmAmdHandler& handler, const char* pseudoOpPlace,
1047                      const char* linePtr)
1048{
1049    Assembler& asmr = handler.assembler;
1050    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1051        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1052        PSEUDOOP_RETURN_BY_ERROR("Illegal place of configuration pseudo-op")
1053    cxuint dimMask = 0;
1054    if (!parseDimensions(asmr, linePtr, dimMask))
1055        return;
1056    if (!checkGarbagesAtEnd(asmr, linePtr))
1057        return;
1058    handler.output.kernels[asmr.currentKernel].config.dimMask = dimMask;
1059}
1060
1061/* argument type map - value is cxuint for getEnumaration */
1062static const std::pair<const char*, cxuint> argTypeNameMap[] =
1063{
1064    { "char", cxuint(KernelArgType::CHAR) },
1065    { "char16", cxuint(KernelArgType::CHAR16) },
1066    { "char2", cxuint(KernelArgType::CHAR2) },
1067    { "char3", cxuint(KernelArgType::CHAR3) },
1068    { "char4", cxuint(KernelArgType::CHAR4) },
1069    { "char8", cxuint(KernelArgType::CHAR8) },
1070    { "clkevent", cxuint(KernelArgType::CLKEVENT) },
1071    { "counter32", cxuint(KernelArgType::COUNTER32) },
1072    { "counter64", cxuint(KernelArgType::COUNTER64) },
1073    { "double", cxuint(KernelArgType::DOUBLE) },
1074    { "double16", cxuint(KernelArgType::DOUBLE16) },
1075    { "double2", cxuint(KernelArgType::DOUBLE2) },
1076    { "double3", cxuint(KernelArgType::DOUBLE3) },
1077    { "double4", cxuint(KernelArgType::DOUBLE4) },
1078    { "double8", cxuint(KernelArgType::DOUBLE8) },
1079    { "float", cxuint(KernelArgType::FLOAT) },
1080    { "float16", cxuint(KernelArgType::FLOAT16) },
1081    { "float2", cxuint(KernelArgType::FLOAT2) },
1082    { "float3", cxuint(KernelArgType::FLOAT3) },
1083    { "float4", cxuint(KernelArgType::FLOAT4) },
1084    { "float8", cxuint(KernelArgType::FLOAT8) },
1085    { "image", cxuint(KernelArgType::IMAGE) },
1086    { "image1d", cxuint(KernelArgType::IMAGE1D) },
1087    { "image1d_array", cxuint(KernelArgType::IMAGE1D_ARRAY) },
1088    { "image1d_buffer", cxuint(KernelArgType::IMAGE1D_BUFFER) },
1089    { "image2d", cxuint(KernelArgType::IMAGE2D) },
1090    { "image2d_array", cxuint(KernelArgType::IMAGE2D_ARRAY) },
1091    { "image3d", cxuint(KernelArgType::IMAGE3D) },
1092    { "int", cxuint(KernelArgType::INT) },
1093    { "int16", cxuint(KernelArgType::INT16) },
1094    { "int2", cxuint(KernelArgType::INT2) },
1095    { "int3", cxuint(KernelArgType::INT3) },
1096    { "int4", cxuint(KernelArgType::INT4) },
1097    { "int8", cxuint(KernelArgType::INT8) },
1098    { "long", cxuint(KernelArgType::LONG) },
1099    { "long16", cxuint(KernelArgType::LONG16) },
1100    { "long2", cxuint(KernelArgType::LONG2) },
1101    { "long3", cxuint(KernelArgType::LONG3) },
1102    { "long4", cxuint(KernelArgType::LONG4) },
1103    { "long8", cxuint(KernelArgType::LONG8) },
1104    { "pipe", cxuint(KernelArgType::PIPE) },
1105    { "queue", cxuint(KernelArgType::CMDQUEUE) },
1106    { "sampler", cxuint(KernelArgType::SAMPLER) },
1107    { "short", cxuint(KernelArgType::SHORT) },
1108    { "short16", cxuint(KernelArgType::SHORT16) },
1109    { "short2", cxuint(KernelArgType::SHORT2) },
1110    { "short3", cxuint(KernelArgType::SHORT3) },
1111    { "short4", cxuint(KernelArgType::SHORT4) },
1112    { "short8", cxuint(KernelArgType::SHORT8) },
1113    { "structure", cxuint(KernelArgType::STRUCTURE) },
1114    { "uchar", cxuint(KernelArgType::UCHAR) },
1115    { "uchar16", cxuint(KernelArgType::UCHAR16) },
1116    { "uchar2", cxuint(KernelArgType::UCHAR2) },
1117    { "uchar3", cxuint(KernelArgType::UCHAR3) },
1118    { "uchar4", cxuint(KernelArgType::UCHAR4) },
1119    { "uchar8", cxuint(KernelArgType::UCHAR8) },
1120    { "uint", cxuint(KernelArgType::UINT) },
1121    { "uint16", cxuint(KernelArgType::UINT16) },
1122    { "uint2", cxuint(KernelArgType::UINT2) },
1123    { "uint3", cxuint(KernelArgType::UINT3) },
1124    { "uint4", cxuint(KernelArgType::UINT4) },
1125    { "uint8", cxuint(KernelArgType::UINT8) },
1126    { "ulong", cxuint(KernelArgType::ULONG)},
1127    { "ulong16", cxuint(KernelArgType::ULONG16) },
1128    { "ulong2", cxuint(KernelArgType::ULONG2) },
1129    { "ulong3", cxuint(KernelArgType::ULONG3) },
1130    { "ulong4", cxuint(KernelArgType::ULONG4) },
1131    { "ulong8", cxuint(KernelArgType::ULONG8) },
1132    { "ushort", cxuint(KernelArgType::USHORT) },
1133    { "ushort16", cxuint(KernelArgType::USHORT16) },
1134    { "ushort2", cxuint(KernelArgType::USHORT2) },
1135    { "ushort3", cxuint(KernelArgType::USHORT3) },
1136    { "ushort4", cxuint(KernelArgType::USHORT4) },
1137    { "ushort8", cxuint(KernelArgType::USHORT8) },
1138    { "void", cxuint(KernelArgType::VOID) }
1139};
1140
1141static const char* defaultArgTypeNames[] = 
1142{
1143    "void", "uchar", "char", "ushort", "short", "uint", "int",
1144    "ulong", "long", "float", "double", "pointer", "image2d_t",
1145    "image1d_t", "image1d_array_t", "image1d_buffer_t",
1146    "image2d_t", "image2d_array_t", "image3d_t",
1147    "uchar2", "uchar3", "uchar4", "uchar8", "uchar16",
1148    "char2", "char3", "char4", "char8", "char16",
1149    "ushort2", "ushort3", "ushort4", "ushort8", "ushort16",
1150    "short2", "short3", "short4", "short8", "short16",
1151    "uint2", "uint3", "uint4", "uint8", "uint16",
1152    "int2", "int3", "int4", "int8", "int16",
1153    "ulong2", "ulong3", "ulong4", "ulong8", "ulong16",
1154    "long2", "long3", "long4", "long8", "long16",
1155    "float2", "float3", "float4", "float8", "float16",
1156    "double2", "double3", "double4", "double8", "double16",
1157    "sampler_t", "structure", "counter32_t", "counter64_t",
1158    "pipe", "queue_t", "clk_event_t"
1159};
1160
1161static const size_t argTypeNameMapSize = sizeof(argTypeNameMap) /
1162        sizeof(std::pair<const char*, KernelArgType>);
1163
1164// main routine to parse argument
1165bool AsmAmdPseudoOps::parseArg(Assembler& asmr, const char* pseudoOpPlace,
1166          const char* linePtr, const std::unordered_set<CString>& argNamesSet,
1167          AmdKernelArgInput& argInput, bool cl20)
1168{
1169    CString argName;
1170    const char* end = asmr.line + asmr.lineSize;
1171    const char* argNamePlace = linePtr;
1172   
1173    bool good = getNameArg(asmr, argName, linePtr, "argument name", true);
1174    if (argNamesSet.find(argName) != argNamesSet.end())
1175        // if found kernel arg with this same name
1176        ASM_NOTGOOD_BY_ERROR(argNamePlace, (std::string("Kernel argument '")+
1177                    argName.c_str()+"' is already defined").c_str())
1178   
1179    if (!skipRequiredComma(asmr, linePtr))
1180        return false;
1181   
1182    skipSpacesToEnd(linePtr, end);
1183    bool typeNameDefined = false;
1184    std::string typeName;
1185    if (linePtr!=end && *linePtr=='"')
1186    {
1187        // if type name defined by user
1188        good &= asmr.parseString(typeName, linePtr);
1189        if (!skipRequiredComma(asmr, linePtr))
1190            return false;
1191        typeNameDefined = true;
1192    }
1193   
1194    bool pointer = false;
1195    KernelArgType argType = KernelArgType::VOID;
1196    char name[20];
1197    skipSpacesToEnd(linePtr, end);
1198    const char* argTypePlace = linePtr;
1199    cxuint argTypeValue;
1200    if (getEnumeration(asmr, linePtr, "argument type", argTypeNameMapSize, argTypeNameMap,
1201                    argTypeValue))
1202    {
1203        argType = KernelArgType(argTypeValue);
1204        if (cl20 || argType <= KernelArgType::MAX_VALUE)
1205        {
1206            skipSpacesToEnd(linePtr, end);
1207            if (linePtr!=end && *linePtr == '*')
1208            {
1209                pointer = true; // if is pointer
1210                linePtr++;
1211            }
1212        }
1213        else
1214        {
1215            // if not OpenCL 2.0 and argument type only present in OpenCL 2.0
1216            skipSpacesToEnd(linePtr, end);
1217            ASM_NOTGOOD_BY_ERROR(linePtr, "Unknown argument type")
1218        }
1219    }
1220    else // if failed
1221        good = false;
1222   
1223    if (!pointer && argType == KernelArgType::COUNTER64)
1224        ASM_NOTGOOD_BY_ERROR(argTypePlace, "Unsupported counter64 type")
1225    if (pointer && (isKernelArgImage(argType) ||
1226            argType == KernelArgType::SAMPLER || argType == KernelArgType::POINTER ||
1227            argType == KernelArgType::COUNTER32 || argType == KernelArgType::COUNTER64))
1228        ASM_NOTGOOD_BY_ERROR(argTypePlace, "Illegal pointer type")
1229   
1230    if (!typeNameDefined)
1231    {
1232        // if type name is not supplied
1233        typeName = defaultArgTypeNames[cxuint(argType)];
1234        if (pointer)
1235            typeName.push_back('*');
1236    }
1237   
1238    KernelPtrSpace ptrSpace = KernelPtrSpace::NONE;
1239    cxbyte ptrAccess = 0;
1240    uint64_t structSizeVal = 0;
1241    uint64_t constSpaceSizeVal = 0;
1242    uint64_t resIdVal = BINGEN_DEFAULT;
1243    cxbyte usedArg = (cl20) ? 3 : 1;
1244   
1245    bool haveComma;
1246    bool haveLastArgument = false;
1247    if (pointer)
1248    {
1249        // if type is pointer
1250        if (argType == KernelArgType::STRUCTURE)
1251        {
1252            if (!skipRequiredComma(asmr, linePtr))
1253                return false;
1254            skipSpacesToEnd(linePtr, end);
1255            // parse extra structure size
1256            const char* structSizePlace = linePtr;
1257            if (getAbsoluteValueArg(asmr, structSizeVal, linePtr, true))
1258                asmr.printWarningForRange(sizeof(cxuint)<<3, structSizeVal,
1259                                  asmr.getSourcePos(structSizePlace), WS_UNSIGNED);
1260            else
1261                good = false;
1262        }
1263       
1264        if (!skipRequiredComma(asmr, linePtr))
1265            return false;
1266        skipSpacesToEnd(linePtr, end);
1267        const char* ptrSpacePlace = linePtr;
1268        // parse ptrSpace
1269        if (getNameArg(asmr, 10, name, linePtr, "pointer space", true))
1270        {
1271            toLowerString(name);
1272            if (::strcmp(name, "local")==0)
1273                ptrSpace = KernelPtrSpace::LOCAL;
1274            else if (::strcmp(name, "global")==0)
1275                ptrSpace = KernelPtrSpace::GLOBAL;
1276            else if (::strcmp(name, "constant")==0)
1277                ptrSpace = KernelPtrSpace::CONSTANT;
1278            else // not known or not given
1279                ASM_NOTGOOD_BY_ERROR(ptrSpacePlace, "Unknown pointer space")
1280        }
1281        else
1282            good = false;
1283       
1284        if (!skipComma(asmr, haveComma, linePtr))
1285            return false;
1286        if (haveComma)
1287        {
1288            // parse ptr access
1289            while (linePtr!=end && *linePtr!=',')
1290            {
1291                skipSpacesToEnd(linePtr, end);
1292                if (linePtr==end || *linePtr==',')
1293                    break;
1294                const char* ptrAccessPlace = linePtr;
1295                // parse acces qualifier (const,restrict,volatile)
1296                if (getNameArg(asmr, 10, name, linePtr, "access qualifier", true))
1297                {
1298                    if (::strcasecmp(name, "const")==0)
1299                        ptrAccess |= KARG_PTR_CONST;
1300                    else if (::strcasecmp(name, "restrict")==0)
1301                        ptrAccess |= KARG_PTR_RESTRICT;
1302                    else if (::strcasecmp(name, "volatile")==0)
1303                        ptrAccess |= KARG_PTR_VOLATILE;
1304                    else
1305                        ASM_NOTGOOD_BY_ERROR(ptrAccessPlace, "Unknown access qualifier")
1306                }
1307                else
1308                    good = false;
1309            }
1310           
1311            bool havePrevArgument = false;
1312            const char* place;
1313            if (ptrSpace == KernelPtrSpace::CONSTANT && !cl20)
1314            {
1315                /* parse constant space size for constant pointer */
1316                if (!skipComma(asmr, haveComma, linePtr))
1317                    return false;
1318                if (haveComma)
1319                {
1320                    skipSpacesToEnd(linePtr, end);
1321                    const char* place = linePtr;
1322                    if (getAbsoluteValueArg(asmr, constSpaceSizeVal, linePtr, false))
1323                        asmr.printWarningForRange(sizeof(cxuint)<<3, constSpaceSizeVal,
1324                                          asmr.getSourcePos(place), WS_UNSIGNED);
1325                    else
1326                        good = false;
1327                    havePrevArgument = true;
1328                }
1329            }
1330            else
1331                havePrevArgument = true;
1332           
1333            if (havePrevArgument && ptrSpace != KernelPtrSpace::LOCAL && !cl20)
1334            {
1335                /* global and constant have resource id (uavId) */
1336                if (!skipComma(asmr, haveComma, linePtr))
1337                    return false;
1338                if (haveComma)
1339                {
1340                    haveLastArgument = true;
1341                    skipSpacesToEnd(linePtr, end);
1342                    place = linePtr;
1343                    if (getAbsoluteValueArg(asmr, resIdVal, linePtr, false))
1344                    {
1345                        // for constant buffers, uavid is in range (0-159)
1346                        const cxuint maxUavId = (ptrSpace==KernelPtrSpace::CONSTANT) ?
1347                                159 : 1023;
1348                       
1349                        if (resIdVal != BINGEN_DEFAULT && resIdVal > maxUavId)
1350                        {
1351                            char buf[80];
1352                            snprintf(buf, 80, "UAVId out of range (0-%u)", maxUavId);
1353                            ASM_NOTGOOD_BY_ERROR(place, buf)
1354                        }
1355                    }
1356                    else
1357                        good = false;
1358                }
1359            }
1360            else
1361                haveLastArgument = havePrevArgument;
1362        }
1363    }
1364    else if (!pointer && isKernelArgImage(argType))
1365    {
1366        // if image type
1367        ptrSpace = KernelPtrSpace::GLOBAL;
1368        ptrAccess = KARG_PTR_READ_ONLY;
1369        if (!skipComma(asmr, haveComma, linePtr))
1370            return false;
1371        if (haveComma)
1372        {
1373            skipSpacesToEnd(linePtr, end);
1374            const char* ptrAccessPlace = linePtr;
1375            // access qualifier for image (rdonly,wronly)
1376            if (getNameArg(asmr, 15, name, linePtr, "access qualifier", false))
1377            {
1378                if (::strcmp(name, "read_only")==0 || ::strcmp(name, "rdonly")==0)
1379                    ptrAccess = KARG_PTR_READ_ONLY;
1380                else if (::strcmp(name, "write_only")==0 || ::strcmp(name, "wronly")==0)
1381                    ptrAccess = KARG_PTR_WRITE_ONLY;
1382                else if (*name!=0) // unknown
1383                    ASM_NOTGOOD_BY_ERROR(ptrAccessPlace, "Unknown access qualifier")
1384            }
1385            else
1386                good = false;
1387           
1388            if (!skipComma(asmr, haveComma, linePtr))
1389                return false;
1390            if (haveComma)
1391            {
1392                haveLastArgument = true;
1393                skipSpacesToEnd(linePtr, end);
1394                const char* place = linePtr;
1395                // resid for image (0-7 for write-only images, 0-127 for read-only images)
1396                if (getAbsoluteValueArg(asmr, resIdVal, linePtr, false))
1397                {
1398                    cxuint maxResId = (ptrAccess == KARG_PTR_READ_ONLY) ? 127 : 7;
1399                    if (resIdVal!=BINGEN_DEFAULT && resIdVal > maxResId)
1400                    {
1401                        char buf[80];
1402                        snprintf(buf, 80, "Resource Id out of range (0-%u)", maxResId);
1403                        ASM_NOTGOOD_BY_ERROR(place, buf)
1404                    }
1405                }
1406                else
1407                    good = false;
1408            }
1409        }
1410    }
1411    else if (!pointer && ((!cl20 && argType == KernelArgType::COUNTER32) ||
1412            (cl20 && argType == KernelArgType::SAMPLER)))
1413    {
1414        // counter uavId
1415        if (!skipComma(asmr, haveComma, linePtr))
1416            return false;
1417        if (haveComma)
1418        {
1419            haveLastArgument = true;
1420            skipSpacesToEnd(linePtr, end);
1421            const char* place = linePtr;
1422            if (getAbsoluteValueArg(asmr, resIdVal, linePtr, true))
1423            {
1424                // for OpenCL 1.2 is - resid in 0-7
1425                if (resIdVal!=BINGEN_DEFAULT && (!cl20 && resIdVal > 7))
1426                    ASM_NOTGOOD_BY_ERROR(place, "Resource Id out of range (0-7)")
1427                    // for OpenCL 1.2 is - resid in 0-15
1428                else if (resIdVal!=BINGEN_DEFAULT && cl20 && resIdVal > 15)
1429                    ASM_NOTGOOD_BY_ERROR(place, "Sampler Id out of range (0-15)")
1430            }
1431            else
1432                good = false;
1433        }
1434    }
1435    else if (!pointer && argType == KernelArgType::STRUCTURE)
1436    {
1437        /* parse structure size */
1438        if (!skipRequiredComma(asmr, linePtr))
1439            return false;
1440        skipSpacesToEnd(linePtr, end);
1441        const char* structSizePlace = linePtr;
1442        if (getAbsoluteValueArg(asmr, structSizeVal, linePtr, true))
1443            asmr.printWarningForRange(sizeof(cxuint)<<3, structSizeVal,
1444                              asmr.getSourcePos(structSizePlace), WS_UNSIGNED);
1445        else
1446            good = false;
1447        haveLastArgument = true;
1448    }
1449    else
1450        haveLastArgument = true;
1451   
1452    /* last argument is 'used' - indicate whether argument is used by kernel */
1453    if (haveLastArgument)
1454    {
1455        if (!skipComma(asmr, haveComma, linePtr))
1456            return false;
1457        if (haveComma)
1458        {
1459            skipSpacesToEnd(linePtr, end);
1460            const char* place = linePtr;
1461            good &= getNameArg(asmr, 10, name, linePtr, "unused specifier");
1462            toLowerString(name);
1463            if (::strcmp(name, "unused")==0)
1464                usedArg = false;
1465            else if (cl20 && ::strcmp(name, "rdonly")==0)
1466                usedArg = 1;
1467            else if (cl20 && ::strcmp(name, "wronly")==0)
1468                usedArg = 2;
1469            else
1470                ASM_NOTGOOD_BY_ERROR(place, "This is not 'unused' specifier")
1471        }
1472    }
1473   
1474    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1475        return false;
1476   
1477    argInput = { argName, typeName, (pointer) ? KernelArgType::POINTER :  argType,
1478        (pointer) ? argType : KernelArgType::VOID, ptrSpace, ptrAccess,
1479        cxuint(structSizeVal), size_t(constSpaceSizeVal), uint32_t(resIdVal), usedArg };
1480    return true;
1481}
1482
1483void AsmAmdPseudoOps::doArg(AsmAmdHandler& handler, const char* pseudoOpPlace,
1484                      const char* linePtr)
1485{
1486    Assembler& asmr = handler.assembler;
1487    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1488        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1489        PSEUDOOP_RETURN_BY_ERROR("Illegal place of kernel argument")
1490   
1491    auto& kernelState = *handler.kernelStates[asmr.currentKernel];
1492    AmdKernelArgInput argInput;
1493    if (!parseArg(asmr, pseudoOpPlace, linePtr, kernelState.argNamesSet, argInput, false))
1494        return;
1495    /* setup argument */
1496    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
1497    const CString argName = argInput.argName;
1498    config.args.push_back(std::move(argInput));
1499    /// put argName
1500    kernelState.argNamesSet.insert(argName);
1501}
1502
1503}
1504
1505bool AsmAmdHandler::parsePseudoOp(const CString& firstName,
1506       const char* stmtPlace, const char* linePtr)
1507{
1508    const size_t pseudoOp = binaryFind(amdPseudoOpNamesTbl, amdPseudoOpNamesTbl +
1509                    sizeof(amdPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
1510                   CStringLess()) - amdPseudoOpNamesTbl;
1511   
1512    switch(pseudoOp)
1513    {
1514        case AMDOP_ARG:
1515            AsmAmdPseudoOps::doArg(*this, stmtPlace, linePtr);
1516            break;
1517        case AMDOP_BOOLCONSTS:
1518            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1519                            CALNOTE_ATI_BOOL32CONSTS);
1520            break;
1521        case AMDOP_CALNOTE:
1522            AsmAmdPseudoOps::addCustomCALNote(*this, stmtPlace, linePtr);
1523            break;
1524        case AMDOP_CBID:
1525            AsmAmdPseudoOps::doCBId(*this, stmtPlace, linePtr);
1526            break;
1527        case AMDOP_CBMASK:
1528            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1529                         1U<<CALNOTE_ATI_CONSTANT_BUFFERS, "cbmask");
1530            break;
1531        case AMDOP_COMPILE_OPTIONS:
1532            AsmAmdPseudoOps::setCompileOptions(*this, linePtr);
1533            break;
1534        case AMDOP_CONDOUT:
1535            AsmAmdPseudoOps::doCondOut(*this, stmtPlace, linePtr);
1536            break;
1537        case AMDOP_CONFIG:
1538            AsmAmdPseudoOps::doConfig(*this, stmtPlace, linePtr);
1539            break;
1540        case AMDOP_CONSTANTBUFFERS:
1541            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1542                            CALNOTE_ATI_CONSTANT_BUFFERS);
1543            break;
1544        case AMDOP_CWS:
1545        case AMDOP_REQD_WORK_GROUP_SIZE:
1546            AsmAmdPseudoOps::setCWS(*this, stmtPlace, linePtr);
1547            break;
1548        case AMDOP_DIMS:
1549            AsmAmdPseudoOps::setDimensions(*this, stmtPlace, linePtr);
1550            break;
1551        case AMDOP_DRIVER_INFO:
1552            AsmAmdPseudoOps::setDriverInfo(*this, linePtr);
1553            break;
1554        case AMDOP_DRIVER_VERSION:
1555            AsmAmdPseudoOps::setDriverVersion(*this, linePtr);
1556            break;
1557        case AMDOP_EARLYEXIT:
1558            AsmAmdPseudoOps::doEarlyExit(*this, stmtPlace, linePtr);
1559            break;
1560        case AMDOP_ENTRY:
1561            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1562                         (1U<<CALNOTE_ATI_PROGINFO) | (1<<CALNOTE_ATI_UAV), "entry");
1563            break;
1564        case AMDOP_EXCEPTIONS:
1565            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_EXCEPTIONS);
1566            break;
1567        case AMDOP_FLOATCONSTS:
1568            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1569                            CALNOTE_ATI_FLOAT32CONSTS);
1570            break;
1571        case AMDOP_FLOATMODE:
1572            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_FLOATMODE);
1573            break;
1574        case AMDOP_GETDRVVER:
1575            AsmAmdPseudoOps::getDriverVersion(*this, linePtr);
1576            break;
1577        case AMDOP_GLOBALBUFFERS:
1578            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1579                            CALNOTE_ATI_GLOBAL_BUFFERS);
1580            break;
1581        case AMDOP_GLOBALDATA:
1582            AsmAmdPseudoOps::doGlobalData(*this, stmtPlace, linePtr);
1583            break;
1584        case AMDOP_HEADER:
1585            AsmAmdPseudoOps::addHeader(*this, stmtPlace, linePtr);
1586            break;
1587        case AMDOP_HWLOCAL:
1588        case AMDOP_LOCALSIZE:
1589            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_HWLOCAL);
1590            break;
1591        case AMDOP_HWREGION:
1592            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_HWREGION);
1593            break;
1594        case AMDOP_IEEEMODE:
1595            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1596                                AMDCVAL_IEEEMODE);
1597            break;
1598        case AMDOP_INPUTS:
1599            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1600                            CALNOTE_ATI_INPUTS);
1601            break;
1602        case AMDOP_INPUTSAMPLERS:
1603            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1604                            CALNOTE_ATI_INPUT_SAMPLERS);
1605            break;
1606        case AMDOP_INTCONSTS:
1607            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1608                            CALNOTE_ATI_INT32CONSTS);
1609            break;
1610        case AMDOP_METADATA:
1611            AsmAmdPseudoOps::addMetadata(*this, stmtPlace, linePtr);
1612            break;
1613        case AMDOP_OUTPUTS:
1614            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1615                            CALNOTE_ATI_OUTPUTS);
1616            break;
1617        case AMDOP_PERSISTENTBUFFERS:
1618            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1619                            CALNOTE_ATI_PERSISTENT_BUFFERS);
1620            break;
1621        case AMDOP_PGMRSRC2:
1622            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PGMRSRC2);
1623            break;
1624        case AMDOP_PRINTFID:
1625            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PRINTFID);
1626            break;
1627        case AMDOP_PRIVATEID:
1628            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PRIVATEID);
1629            break;
1630        case AMDOP_PROGINFO:
1631            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1632                            CALNOTE_ATI_PROGINFO);
1633            break;
1634        case AMDOP_SAMPLER:
1635            AsmAmdPseudoOps::doSampler(*this, stmtPlace, linePtr);
1636            break;
1637        case AMDOP_SCRATCHBUFFER:
1638            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1639                                AMDCVAL_SCRATCHBUFFER);
1640            break;
1641        case AMDOP_SCRATCHBUFFERS:
1642            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1643                            CALNOTE_ATI_SCRATCH_BUFFERS);
1644            break;
1645        case AMDOP_SEGMENT:
1646            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1647                    (1U<<CALNOTE_ATI_INT32CONSTS) | (1U<<CALNOTE_ATI_FLOAT32CONSTS) |
1648                    (1U<<CALNOTE_ATI_BOOL32CONSTS), "segment");
1649            break;
1650        case AMDOP_SGPRSNUM:
1651            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_SGPRSNUM);
1652            break;
1653        case AMDOP_SUBCONSTANTBUFFERS:
1654            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1655                            CALNOTE_ATI_SUB_CONSTANT_BUFFERS);
1656            break;
1657        case AMDOP_TGSIZE:
1658            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1659                            AMDCVAL_TGSIZE);
1660            break;
1661        case AMDOP_UAV:
1662            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1663                            CALNOTE_ATI_UAV);
1664            break;
1665        case AMDOP_UAVID:
1666            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_UAVID);
1667            break;
1668        case AMDOP_UAVMAILBOXSIZE:
1669            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1670                            CALNOTE_ATI_UAV_MAILBOX_SIZE);
1671            break;
1672        case AMDOP_UAVOPMASK:
1673            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1674                            CALNOTE_ATI_UAV_OP_MASK);
1675            break;
1676        case AMDOP_UAVPRIVATE:
1677            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_UAVPRIVATE);
1678            break;
1679        case AMDOP_USECONSTDATA:
1680            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1681                            AMDCVAL_USECONSTDATA);
1682            break;
1683        case AMDOP_USEPRINTF:
1684            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1685                            AMDCVAL_USEPRINTF);
1686            break;
1687        case AMDOP_USERDATA:
1688            AsmAmdPseudoOps::addUserData(*this, stmtPlace, linePtr);
1689            break;
1690        case AMDOP_VGPRSNUM:
1691            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_VGPRSNUM);
1692            break;
1693        default:
1694            return false;
1695    }
1696    return true;
1697}
1698
1699bool AsmAmdHandler::prepareBinary()
1700{
1701    if (assembler.isaAssembler!=nullptr)
1702        saveCurrentAllocRegs(); // save last kernel allocated registers to kernel state
1703   
1704    output.is64Bit = assembler.is64Bit();
1705    output.deviceType = assembler.getDeviceType();
1706    /* initialize sections */
1707    const size_t sectionsNum = sections.size();
1708    const size_t kernelsNum = kernelStates.size();
1709   
1710    // set sections as outputs
1711    for (size_t i = 0; i < sectionsNum; i++)
1712    {
1713        const AsmSection& asmSection = assembler.sections[i];
1714        const Section& section = sections[i];
1715        const size_t sectionSize = asmSection.getSize();
1716        const cxbyte* sectionData = (!asmSection.content.empty()) ?
1717                asmSection.content.data() : (const cxbyte*)"";
1718        AmdKernelInput* kernel = (section.kernelId!=ASMKERN_GLOBAL) ?
1719                    &output.kernels[section.kernelId] : nullptr;
1720               
1721        switch(asmSection.type)
1722        {
1723            case AsmSectionType::CODE:
1724                kernel->codeSize = sectionSize;
1725                kernel->code = sectionData;
1726                break;
1727            case AsmSectionType::AMD_HEADER:
1728                kernel->headerSize = sectionSize;
1729                kernel->header = sectionData;
1730                break;
1731            case AsmSectionType::AMD_METADATA:
1732                kernel->metadataSize = sectionSize;
1733                kernel->metadata = (const char*)sectionData;
1734                break;
1735            case AsmSectionType::DATA:
1736                if (section.kernelId == ASMKERN_GLOBAL)
1737                {
1738                    // this is global data
1739                    if (sectionSize!=0)
1740                    {
1741                        output.globalDataSize = sectionSize;
1742                        output.globalData = sectionData;
1743                    }
1744                }
1745                else
1746                {
1747                    // this is kernel data
1748                    kernel->dataSize = sectionSize;
1749                    kernel->data = sectionData;
1750                }
1751                break;
1752            case AsmSectionType::AMD_CALNOTE:
1753            {
1754                // add new CAL note to output
1755                CALNoteInput calNote;
1756                calNote.header.type = section.extraId;
1757                calNote.header.descSize = sectionSize;
1758                calNote.header.nameSize = 8;
1759                ::memcpy(calNote.header.name, "ATI CAL", 8);
1760                calNote.data = sectionData;
1761                kernel->calNotes.push_back(calNote);
1762                break;
1763            }
1764            case AsmSectionType::EXTRA_PROGBITS:
1765            case AsmSectionType::EXTRA_NOTE:
1766            case AsmSectionType::EXTRA_NOBITS:
1767            case AsmSectionType::EXTRA_SECTION:
1768            {
1769                // handle extra (user) section, set section type and its flags
1770                uint32_t elfSectType =
1771                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
1772                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
1773                             SHT_PROGBITS;
1774                uint32_t elfSectFlags = 
1775                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
1776                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
1777                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
1778                // put extra sections to binary
1779                if (section.kernelId == ASMKERN_GLOBAL)
1780                    output.extraSections.push_back({section.name, sectionSize, sectionData,
1781                            asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1782                            elfSectFlags, ELFSECTID_NULL, 0, 0 });
1783                else // to inner binary
1784                    kernel->extraSections.push_back({section.name, sectionSize, sectionData,
1785                            asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1786                            elfSectFlags, ELFSECTID_NULL, 0, 0 });
1787                break;
1788            }
1789            default: // ignore other sections
1790                break;
1791        }
1792    }
1793   
1794    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
1795    // determine max SGPRs number for architecture excluding VCC
1796    const cxuint maxSGPRsNumWithoutVCC = getGPUMaxRegistersNum(arch, REGTYPE_SGPR,
1797                REGCOUNT_NO_VCC);
1798    // set up number of the allocated SGPRs and VGPRs for kernel
1799    for (size_t i = 0; i < kernelsNum; i++)
1800    {
1801        if (!output.kernels[i].useConfig)
1802            continue;
1803        AmdKernelConfig& config = output.kernels[i].config;
1804        cxuint userSGPRsNum = 0;
1805        /* include userData sgprs */
1806        for (cxuint i = 0; i < config.userDatas.size(); i++)
1807            userSGPRsNum = std::max(userSGPRsNum,
1808                        config.userDatas[i].regStart+config.userDatas[i].regSize);
1809       
1810        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
1811                ((config.pgmRSRC2>>7)&7);
1812        cxuint minRegsNum[2];
1813        // get minimum required register by user data
1814        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
1815                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
1816                   ((config.scratchBufferSize!=0) ? GPUSETUP_SCRATCH_EN : 0), minRegsNum);
1817        // set used SGPRs number if not specified by user
1818        if (config.usedSGPRsNum==BINGEN_DEFAULT)
1819            config.usedSGPRsNum = std::min(maxSGPRsNumWithoutVCC,
1820                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]));
1821        if (config.usedVGPRsNum==BINGEN_DEFAULT)
1822            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
1823    }
1824   
1825    /* put extra symbols */
1826    if (assembler.flags & ASM_FORCE_ADD_SYMBOLS)
1827        for (const AsmSymbolEntry& symEntry: assembler.globalScope.symbolMap)
1828        {
1829            if (!symEntry.second.hasValue ||
1830                ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
1831                continue; // unresolved or local
1832            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
1833                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
1834            if (binSectId==ELFSECTID_UNDEF)
1835                continue; // no section
1836           
1837            const BinSymbol binSym = { symEntry.first, symEntry.second.value,
1838                        symEntry.second.size, binSectId, false, symEntry.second.info,
1839                        symEntry.second.other };
1840           
1841            if (symEntry.second.sectionId == ASMSECT_ABS ||
1842                sections[symEntry.second.sectionId].kernelId == ASMKERN_GLOBAL)
1843                output.extraSymbols.push_back(std::move(binSym));
1844            else // to kernel extra symbols
1845                output.kernels[sections[symEntry.second.sectionId].kernelId].extraSymbols
1846                            .push_back(std::move(binSym));
1847        }
1848    // driver version setup
1849    if (output.driverVersion==0 && output.driverInfo.empty() &&
1850        (assembler.flags&ASM_TESTRUN)==0)
1851    {
1852        if (assembler.driverVersion==0) // just detect driver version
1853            output.driverVersion = detectedDriverVersion;
1854        else // from assembler setup
1855            output.driverVersion = assembler.driverVersion;
1856    }
1857    return true;
1858}
1859
1860void AsmAmdHandler::writeBinary(std::ostream& os) const
1861{
1862    AmdGPUBinGenerator binGenerator(&output);
1863    binGenerator.generate(os);
1864}
1865
1866void AsmAmdHandler::writeBinary(Array<cxbyte>& array) const
1867{
1868    AmdGPUBinGenerator binGenerator(&output);
1869    binGenerator.generate(array);
1870}
Note: See TracBrowser for help on using the repository browser.