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

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

CLRadeonExtender: Asm: Move parsring of dimensions to AsmParseUtils?.

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