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

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

CLRadeonExtender: Asm: Correct default values for CWS (reqd_work_group_size) and other work group size parameters.

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