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

Last change on this file since 2390 was 2390, checked in by matszpk, 4 years ago

CLRadeonExtender: Introduce isKernelArgImage to determine whether argument type is image.

File size: 71.5 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    const char* end = asmr.line + asmr.lineSize;
1100    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1101        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1102    {
1103        asmr.printError(pseudoOpPlace, "Illegal place of configuration pseudo-op");
1104        return;
1105    }
1106    skipSpacesToEnd(linePtr, end);
1107    const char* dimPlace = linePtr;
1108    char buf[10];
1109    cxuint dimMask = 0;
1110    if (getNameArg(asmr, 10, buf, linePtr, "dimension set", false))
1111    {
1112        toLowerString(buf);
1113        for (cxuint i = 0; buf[i]!=0; i++)
1114            if (buf[i]=='x')
1115                dimMask |= 1;
1116            else if (buf[i]=='y')
1117                dimMask |= 2;
1118            else if (buf[i]=='z')
1119                dimMask |= 4;
1120            else
1121            {
1122                asmr.printError(dimPlace, "Unknown dimension type");
1123                return;
1124            }
1125    }
1126    else // error
1127        return;
1128    if (!checkGarbagesAtEnd(asmr, linePtr))
1129        return;
1130    handler.output.kernels[asmr.currentKernel].config.dimMask = dimMask;
1131}
1132
1133/* argument type map - value is cxuint for getEnumaration */
1134static const std::pair<const char*, cxuint> argTypeNameMap[] =
1135{
1136    { "char", cxuint(KernelArgType::CHAR) },
1137    { "char16", cxuint(KernelArgType::CHAR16) },
1138    { "char2", cxuint(KernelArgType::CHAR2) },
1139    { "char3", cxuint(KernelArgType::CHAR3) },
1140    { "char4", cxuint(KernelArgType::CHAR4) },
1141    { "char8", cxuint(KernelArgType::CHAR8) },
1142    { "clkevent", cxuint(KernelArgType::CLKEVENT) },
1143    { "counter32", cxuint(KernelArgType::COUNTER32) },
1144    { "counter64", cxuint(KernelArgType::COUNTER64) },
1145    { "double", cxuint(KernelArgType::DOUBLE) },
1146    { "double16", cxuint(KernelArgType::DOUBLE16) },
1147    { "double2", cxuint(KernelArgType::DOUBLE2) },
1148    { "double3", cxuint(KernelArgType::DOUBLE3) },
1149    { "double4", cxuint(KernelArgType::DOUBLE4) },
1150    { "double8", cxuint(KernelArgType::DOUBLE8) },
1151    { "float", cxuint(KernelArgType::FLOAT) },
1152    { "float16", cxuint(KernelArgType::FLOAT16) },
1153    { "float2", cxuint(KernelArgType::FLOAT2) },
1154    { "float3", cxuint(KernelArgType::FLOAT3) },
1155    { "float4", cxuint(KernelArgType::FLOAT4) },
1156    { "float8", cxuint(KernelArgType::FLOAT8) },
1157    { "image", cxuint(KernelArgType::IMAGE) },
1158    { "image1d", cxuint(KernelArgType::IMAGE1D) },
1159    { "image1d_array", cxuint(KernelArgType::IMAGE1D_ARRAY) },
1160    { "image1d_buffer", cxuint(KernelArgType::IMAGE1D_BUFFER) },
1161    { "image2d", cxuint(KernelArgType::IMAGE2D) },
1162    { "image2d_array", cxuint(KernelArgType::IMAGE2D_ARRAY) },
1163    { "image3d", cxuint(KernelArgType::IMAGE3D) },
1164    { "int", cxuint(KernelArgType::INT) },
1165    { "int16", cxuint(KernelArgType::INT16) },
1166    { "int2", cxuint(KernelArgType::INT2) },
1167    { "int3", cxuint(KernelArgType::INT3) },
1168    { "int4", cxuint(KernelArgType::INT4) },
1169    { "int8", cxuint(KernelArgType::INT8) },
1170    { "long", cxuint(KernelArgType::LONG) },
1171    { "long16", cxuint(KernelArgType::LONG16) },
1172    { "long2", cxuint(KernelArgType::LONG2) },
1173    { "long3", cxuint(KernelArgType::LONG3) },
1174    { "long4", cxuint(KernelArgType::LONG4) },
1175    { "long8", cxuint(KernelArgType::LONG8) },
1176    { "pipe", cxuint(KernelArgType::PIPE) },
1177    { "queue", cxuint(KernelArgType::CMDQUEUE) },
1178    { "sampler", cxuint(KernelArgType::SAMPLER) },
1179    { "short", cxuint(KernelArgType::SHORT) },
1180    { "short16", cxuint(KernelArgType::SHORT16) },
1181    { "short2", cxuint(KernelArgType::SHORT2) },
1182    { "short3", cxuint(KernelArgType::SHORT3) },
1183    { "short4", cxuint(KernelArgType::SHORT4) },
1184    { "short8", cxuint(KernelArgType::SHORT8) },
1185    { "structure", cxuint(KernelArgType::STRUCTURE) },
1186    { "uchar", cxuint(KernelArgType::UCHAR) },
1187    { "uchar16", cxuint(KernelArgType::UCHAR16) },
1188    { "uchar2", cxuint(KernelArgType::UCHAR2) },
1189    { "uchar3", cxuint(KernelArgType::UCHAR3) },
1190    { "uchar4", cxuint(KernelArgType::UCHAR4) },
1191    { "uchar8", cxuint(KernelArgType::UCHAR8) },
1192    { "uint", cxuint(KernelArgType::UINT) },
1193    { "uint16", cxuint(KernelArgType::UINT16) },
1194    { "uint2", cxuint(KernelArgType::UINT2) },
1195    { "uint3", cxuint(KernelArgType::UINT3) },
1196    { "uint4", cxuint(KernelArgType::UINT4) },
1197    { "uint8", cxuint(KernelArgType::UINT8) },
1198    { "ulong", cxuint(KernelArgType::ULONG)},
1199    { "ulong16", cxuint(KernelArgType::ULONG16) },
1200    { "ulong2", cxuint(KernelArgType::ULONG2) },
1201    { "ulong3", cxuint(KernelArgType::ULONG3) },
1202    { "ulong4", cxuint(KernelArgType::ULONG4) },
1203    { "ulong8", cxuint(KernelArgType::ULONG8) },
1204    { "ushort", cxuint(KernelArgType::USHORT) },
1205    { "ushort16", cxuint(KernelArgType::USHORT16) },
1206    { "ushort2", cxuint(KernelArgType::USHORT2) },
1207    { "ushort3", cxuint(KernelArgType::USHORT3) },
1208    { "ushort4", cxuint(KernelArgType::USHORT4) },
1209    { "ushort8", cxuint(KernelArgType::USHORT8) },
1210    { "void", cxuint(KernelArgType::VOID) }
1211};
1212
1213static const char* defaultArgTypeNames[] = 
1214{
1215    "void", "uchar", "char", "ushort", "short", "uint", "int",
1216    "ulong", "long", "float", "double", "pointer", "image2d_t",
1217    "image1d_t", "image1d_array_t", "image1d_buffer_t",
1218    "image2d_t", "image2d_array_t", "image3d_t",
1219    "uchar2", "uchar3", "uchar4", "uchar8", "uchar16",
1220    "char2", "char3", "char4", "char8", "char16",
1221    "ushort2", "ushort3", "ushort4", "ushort8", "ushort16",
1222    "short2", "short3", "short4", "short8", "short16",
1223    "uint2", "uint3", "uint4", "uint8", "uint16",
1224    "int2", "int3", "int4", "int8", "int16",
1225    "ulong2", "ulong3", "ulong4", "ulong8", "ulong16",
1226    "long2", "long3", "long4", "long8", "long16",
1227    "float2", "float3", "float4", "float8", "float16",
1228    "double2", "double3", "double4", "double8", "double16",
1229    "sampler_t", "structure", "counter32_t", "counter64_t",
1230    "pipe", "queue_t", "clk_event_t"
1231};
1232
1233static const size_t argTypeNameMapSize = sizeof(argTypeNameMap) /
1234        sizeof(std::pair<const char*, KernelArgType>);
1235
1236bool AsmAmdPseudoOps::parseArg(Assembler& asmr, const char* pseudoOpPlace,
1237          const char* linePtr, const std::unordered_set<CString>& argNamesSet,
1238          AmdKernelArgInput& argInput, bool cl20)
1239{
1240    CString argName;
1241    const char* end = asmr.line + asmr.lineSize;
1242    const char* argNamePlace = linePtr;
1243   
1244    bool good = getNameArg(asmr, argName, linePtr, "argument name", true);
1245    if (argNamesSet.find(argName) != argNamesSet.end())
1246    {   // if found kernel arg with this same name
1247        asmr.printError(argNamePlace, (std::string("Kernel argument '")+argName.c_str()+
1248                    "' is already defined").c_str());
1249        good = false;
1250    }
1251   
1252    if (!skipRequiredComma(asmr, linePtr))
1253        return false;
1254   
1255    skipSpacesToEnd(linePtr, end);
1256    bool typeNameDefined = false;
1257    std::string typeName;
1258    if (linePtr!=end && *linePtr=='"')
1259    {   // if type name defined by user
1260        good &= asmr.parseString(typeName, linePtr);
1261        if (!skipRequiredComma(asmr, linePtr))
1262            return false;
1263        typeNameDefined = true;
1264    }
1265   
1266    bool pointer = false;
1267    KernelArgType argType = KernelArgType::VOID;
1268    char name[20];
1269    skipSpacesToEnd(linePtr, end);
1270    const char* argTypePlace = linePtr;
1271    cxuint argTypeValue;
1272    if (getEnumeration(asmr, linePtr, "argument type", argTypeNameMapSize, argTypeNameMap,
1273                    argTypeValue))
1274    {
1275        argType = KernelArgType(argTypeValue);
1276        if (cl20 || argType <= KernelArgType::MAX_VALUE)
1277        {
1278            skipSpacesToEnd(linePtr, end);
1279            if (linePtr!=end && *linePtr == '*')
1280            {
1281                pointer = true; // if is pointer
1282                linePtr++;
1283            }
1284        }
1285        else
1286        {   // if not OpenCL 2.0 and argument type only present in OpenCL 2.0
1287            skipSpacesToEnd(linePtr, end);
1288            asmr.printError(linePtr, "Unknown argument type");
1289            good = false;
1290        }
1291    }
1292    else // if failed
1293        good = false;
1294   
1295    if (!pointer && argType == KernelArgType::COUNTER64)
1296    {
1297        asmr.printError(argTypePlace, "Unsupported counter64 type");
1298        good = false;
1299    }
1300    if (pointer && (isKernelArgImage(argType) ||
1301            argType == KernelArgType::SAMPLER || argType == KernelArgType::POINTER ||
1302            argType == KernelArgType::COUNTER32 || argType == KernelArgType::COUNTER64))
1303    {
1304        asmr.printError(argTypePlace, "Illegal pointer type");
1305        good = false;
1306    }
1307   
1308    if (!typeNameDefined)
1309    {
1310        typeName = defaultArgTypeNames[cxuint(argType)];
1311        if (pointer)
1312            typeName.push_back('*');
1313    }
1314   
1315    KernelPtrSpace ptrSpace = KernelPtrSpace::NONE;
1316    cxbyte ptrAccess = 0;
1317    uint64_t structSizeVal = 0;
1318    uint64_t constSpaceSizeVal = 0;
1319    uint64_t resIdVal = BINGEN_DEFAULT;
1320    cxbyte usedArg = (cl20) ? 3 : 1;
1321   
1322    bool haveComma;
1323    bool haveLastArgument = false;
1324    if (pointer)
1325    {
1326        if (argType == KernelArgType::STRUCTURE)
1327        {
1328            if (!skipRequiredComma(asmr, linePtr))
1329                return false;
1330            skipSpacesToEnd(linePtr, end);
1331            const char* structSizePlace = linePtr;
1332            if (getAbsoluteValueArg(asmr, structSizeVal, linePtr, true))
1333                asmr.printWarningForRange(sizeof(cxuint)<<3, structSizeVal,
1334                                  asmr.getSourcePos(structSizePlace), WS_UNSIGNED);
1335            else
1336                good = false;
1337        }
1338       
1339        if (!skipRequiredComma(asmr, linePtr))
1340            return false;
1341        skipSpacesToEnd(linePtr, end);
1342        const char* ptrSpacePlace = linePtr;
1343        // parse ptrSpace
1344        if (getNameArg(asmr, 10, name, linePtr, "pointer space", true))
1345        {
1346            toLowerString(name);
1347            if (::strcmp(name, "local")==0)
1348                ptrSpace = KernelPtrSpace::LOCAL;
1349            else if (::strcmp(name, "global")==0)
1350                ptrSpace = KernelPtrSpace::GLOBAL;
1351            else if (::strcmp(name, "constant")==0)
1352                ptrSpace = KernelPtrSpace::CONSTANT;
1353            else
1354            {   // not known or not given
1355                asmr.printError(ptrSpacePlace, "Unknown pointer space");
1356                good = false;
1357            }
1358        }
1359        else
1360            good = false;
1361       
1362        if (!skipComma(asmr, haveComma, linePtr))
1363            return false;
1364        if (haveComma)
1365        {   // parse ptr access
1366            while (linePtr!=end && *linePtr!=',')
1367            {
1368                skipSpacesToEnd(linePtr, end);
1369                if (linePtr==end || *linePtr==',')
1370                    break;
1371                const char* ptrAccessPlace = linePtr;
1372                if (getNameArg(asmr, 10, name, linePtr, "access qualifier", true))
1373                {
1374                    if (::strcmp(name, "const")==0)
1375                        ptrAccess |= KARG_PTR_CONST;
1376                    else if (::strcmp(name, "restrict")==0)
1377                        ptrAccess |= KARG_PTR_RESTRICT;
1378                    else if (::strcmp(name, "volatile")==0)
1379                        ptrAccess |= KARG_PTR_VOLATILE;
1380                    else
1381                    {
1382                        asmr.printError(ptrAccessPlace, "Unknown access qualifier");
1383                        good = false;
1384                    }
1385                }
1386                else
1387                    good = false;
1388            }
1389           
1390            bool havePrevArgument = false;
1391            const char* place;
1392            if (ptrSpace == KernelPtrSpace::CONSTANT && !cl20)
1393            {   /* parse constant space size for constant pointer */
1394                if (!skipComma(asmr, haveComma, linePtr))
1395                    return false;
1396                if (haveComma)
1397                {
1398                    skipSpacesToEnd(linePtr, end);
1399                    const char* place = linePtr;
1400                    if (getAbsoluteValueArg(asmr, constSpaceSizeVal, linePtr, false))
1401                        asmr.printWarningForRange(sizeof(cxuint)<<3, constSpaceSizeVal,
1402                                          asmr.getSourcePos(place), WS_UNSIGNED);
1403                    else
1404                        good = false;
1405                    havePrevArgument = true;
1406                }
1407            }
1408            else
1409                havePrevArgument = true;
1410           
1411            if (havePrevArgument && ptrSpace != KernelPtrSpace::LOCAL && !cl20)
1412            {   /* global and constant have resource id (uavId) */
1413                if (!skipComma(asmr, haveComma, linePtr))
1414                    return false;
1415                if (haveComma)
1416                {
1417                    haveLastArgument = true;
1418                    skipSpacesToEnd(linePtr, end);
1419                    place = linePtr;
1420                    if (getAbsoluteValueArg(asmr, resIdVal, linePtr, false))
1421                    {
1422                        const cxuint maxUavId = (ptrSpace==KernelPtrSpace::CONSTANT) ?
1423                                159 : 1023;
1424                       
1425                        if (resIdVal != BINGEN_DEFAULT && resIdVal > maxUavId)
1426                        {
1427                            char buf[80];
1428                            snprintf(buf, 80, "UAVId out of range (0-%u)", maxUavId);
1429                            asmr.printError(place, buf);
1430                            good = false;
1431                        }
1432                    }
1433                    else
1434                        good = false;
1435                }
1436            }
1437            else
1438                haveLastArgument = havePrevArgument;
1439        }
1440    }
1441    else if (!pointer && isKernelArgImage(argType))
1442    {
1443        ptrSpace = KernelPtrSpace::GLOBAL;
1444        ptrAccess = KARG_PTR_READ_ONLY;
1445        if (!skipComma(asmr, haveComma, linePtr))
1446            return false;
1447        if (haveComma)
1448        {
1449            skipSpacesToEnd(linePtr, end);
1450            const char* ptrAccessPlace = linePtr;
1451            if (getNameArg(asmr, 15, name, linePtr, "access qualifier", false))
1452            {
1453                if (::strcmp(name, "read_only")==0 || ::strcmp(name, "rdonly")==0)
1454                    ptrAccess = KARG_PTR_READ_ONLY;
1455                else if (::strcmp(name, "write_only")==0 || ::strcmp(name, "wronly")==0)
1456                    ptrAccess = KARG_PTR_WRITE_ONLY;
1457                else if (*name!=0)
1458                {   // unknown
1459                    asmr.printError(ptrAccessPlace, "Unknown access qualifier");
1460                    good = false;
1461                }
1462            }
1463            else
1464                good = false;
1465           
1466            if (!skipComma(asmr, haveComma, linePtr))
1467                return false;
1468            if (haveComma)
1469            {
1470                haveLastArgument = true;
1471                skipSpacesToEnd(linePtr, end);
1472                const char* place = linePtr;
1473                if (getAbsoluteValueArg(asmr, resIdVal, linePtr, false))
1474                {
1475                    cxuint maxResId = (ptrAccess == KARG_PTR_READ_ONLY) ? 127 : 7;
1476                    if (resIdVal!=BINGEN_DEFAULT && resIdVal > maxResId)
1477                    {
1478                        char buf[80];
1479                        snprintf(buf, 80, "Resource Id out of range (0-%u)", maxResId);
1480                        asmr.printError(place, buf);
1481                        good = false;
1482                    }
1483                }
1484                else
1485                    good = false;
1486            }
1487        }
1488    }
1489    else if (!pointer && ((!cl20 && argType == KernelArgType::COUNTER32) ||
1490            (cl20 && argType == KernelArgType::SAMPLER)))
1491    {   // counter uavId
1492        if (!skipComma(asmr, haveComma, linePtr))
1493            return false;
1494        if (haveComma)
1495        {
1496            haveLastArgument = true;
1497            skipSpacesToEnd(linePtr, end);
1498            const char* place = linePtr;
1499            if (getAbsoluteValueArg(asmr, resIdVal, linePtr, true))
1500            {
1501                if (resIdVal!=BINGEN_DEFAULT && (!cl20 && resIdVal > 7))
1502                {
1503                    asmr.printError(place, "Resource Id out of range (0-7)");
1504                    good = false;
1505                }
1506                else if (resIdVal!=BINGEN_DEFAULT && cl20 && resIdVal > 15)
1507                {
1508                    asmr.printError(place, "Sampler Id out of range (0-15)");
1509                    good = false;
1510                }
1511            }
1512            else
1513                good = false;
1514        }
1515    }
1516    else if (!pointer && argType == KernelArgType::STRUCTURE)
1517    {   /* parse structure size */
1518        if (!skipRequiredComma(asmr, linePtr))
1519            return false;
1520        skipSpacesToEnd(linePtr, end);
1521        const char* structSizePlace = linePtr;
1522        if (getAbsoluteValueArg(asmr, structSizeVal, linePtr, true))
1523            asmr.printWarningForRange(sizeof(cxuint)<<3, structSizeVal,
1524                              asmr.getSourcePos(structSizePlace), WS_UNSIGNED);
1525        else
1526            good = false;
1527        haveLastArgument = true;
1528    }
1529    else
1530        haveLastArgument = true;
1531   
1532    /* last argument is 'used' - indicate whether argument is used by kernel */
1533    if (haveLastArgument)
1534    {
1535        if (!skipComma(asmr, haveComma, linePtr))
1536            return false;
1537        if (haveComma)
1538        {
1539            skipSpacesToEnd(linePtr, end);
1540            const char* place = linePtr;
1541            good &= getNameArg(asmr, 10, name, linePtr, "unused specifier");
1542            toLowerString(name);
1543            if (::strcmp(name, "unused")==0)
1544                usedArg = false;
1545            else if (cl20 && ::strcmp(name, "rdonly")==0)
1546                usedArg = 1;
1547            else if (cl20 && ::strcmp(name, "wronly")==0)
1548                usedArg = 2;
1549            else
1550            {
1551                asmr.printError(place, "This is not 'unused' specifier");
1552                good = false;
1553            }
1554        }
1555    }
1556   
1557    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1558        return false;
1559   
1560    argInput = { argName, typeName, (pointer) ? KernelArgType::POINTER :  argType,
1561        (pointer) ? argType : KernelArgType::VOID, ptrSpace, ptrAccess,
1562        cxuint(structSizeVal), size_t(constSpaceSizeVal), uint32_t(resIdVal), usedArg };
1563    return true;
1564}
1565
1566void AsmAmdPseudoOps::doArg(AsmAmdHandler& handler, const char* pseudoOpPlace,
1567                      const char* linePtr)
1568{
1569    Assembler& asmr = handler.assembler;
1570    if (asmr.currentKernel==ASMKERN_GLOBAL ||
1571        asmr.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
1572    {
1573        asmr.printError(pseudoOpPlace, "Illegal place of kernel argument");
1574        return;
1575    }
1576   
1577    auto& kernelState = *handler.kernelStates[asmr.currentKernel];
1578    AmdKernelArgInput argInput;
1579    if (!parseArg(asmr, pseudoOpPlace, linePtr, kernelState.argNamesSet, argInput, false))
1580        return;
1581    /* setup argument */
1582    AmdKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
1583    const CString argName = argInput.argName;
1584    config.args.push_back(std::move(argInput));
1585    /// put argName
1586    kernelState.argNamesSet.insert(argName);
1587}
1588
1589}
1590
1591bool AsmAmdHandler::parsePseudoOp(const CString& firstName,
1592       const char* stmtPlace, const char* linePtr)
1593{
1594    const size_t pseudoOp = binaryFind(amdPseudoOpNamesTbl, amdPseudoOpNamesTbl +
1595                    sizeof(amdPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
1596                   CStringLess()) - amdPseudoOpNamesTbl;
1597   
1598    switch(pseudoOp)
1599    {
1600        case AMDOP_ARG:
1601            AsmAmdPseudoOps::doArg(*this, stmtPlace, linePtr);
1602            break;
1603        case AMDOP_BOOLCONSTS:
1604            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1605                            CALNOTE_ATI_BOOL32CONSTS);
1606            break;
1607        case AMDOP_CALNOTE:
1608            AsmAmdPseudoOps::addCustomCALNote(*this, stmtPlace, linePtr);
1609            break;
1610        case AMDOP_CBID:
1611            AsmAmdPseudoOps::doCBId(*this, stmtPlace, linePtr);
1612            break;
1613        case AMDOP_CBMASK:
1614            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1615                         1U<<CALNOTE_ATI_CONSTANT_BUFFERS, "cbmask");
1616            break;
1617        case AMDOP_COMPILE_OPTIONS:
1618            AsmAmdPseudoOps::setCompileOptions(*this, linePtr);
1619            break;
1620        case AMDOP_CONDOUT:
1621            AsmAmdPseudoOps::doCondOut(*this, stmtPlace, linePtr);
1622            break;
1623        case AMDOP_CONFIG:
1624            AsmAmdPseudoOps::doConfig(*this, stmtPlace, linePtr);
1625            break;
1626        case AMDOP_CONSTANTBUFFERS:
1627            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1628                            CALNOTE_ATI_CONSTANT_BUFFERS);
1629            break;
1630        case AMDOP_CWS:
1631            AsmAmdPseudoOps::setCWS(*this, stmtPlace, linePtr);
1632            break;
1633        case AMDOP_DIMS:
1634            AsmAmdPseudoOps::setDimensions(*this, stmtPlace, linePtr);
1635            break;
1636        case AMDOP_DRIVER_INFO:
1637            AsmAmdPseudoOps::setDriverInfo(*this, linePtr);
1638            break;
1639        case AMDOP_DRIVER_VERSION:
1640            AsmAmdPseudoOps::setDriverVersion(*this, linePtr);
1641            break;
1642        case AMDOP_EARLYEXIT:
1643            AsmAmdPseudoOps::doEarlyExit(*this, stmtPlace, linePtr);
1644            break;
1645        case AMDOP_ENTRY:
1646            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1647                         (1U<<CALNOTE_ATI_PROGINFO) | (1<<CALNOTE_ATI_UAV), "entry");
1648            break;
1649        case AMDOP_EXCEPTIONS:
1650            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_EXCEPTIONS);
1651            break;
1652        case AMDOP_FLOATCONSTS:
1653            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1654                            CALNOTE_ATI_FLOAT32CONSTS);
1655            break;
1656        case AMDOP_FLOATMODE:
1657            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_FLOATMODE);
1658            break;
1659        case AMDOP_GETDRVVER:
1660            AsmAmdPseudoOps::getDriverVersion(*this, linePtr);
1661            break;
1662        case AMDOP_GLOBALBUFFERS:
1663            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1664                            CALNOTE_ATI_GLOBAL_BUFFERS);
1665            break;
1666        case AMDOP_GLOBALDATA:
1667            AsmAmdPseudoOps::doGlobalData(*this, stmtPlace, linePtr);
1668            break;
1669        case AMDOP_HEADER:
1670            AsmAmdPseudoOps::addHeader(*this, stmtPlace, linePtr);
1671            break;
1672        case AMDOP_HWLOCAL:
1673        case AMDOP_LOCALSIZE:
1674            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_HWLOCAL);
1675            break;
1676        case AMDOP_HWREGION:
1677            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_HWREGION);
1678            break;
1679        case AMDOP_IEEEMODE:
1680            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1681                                AMDCVAL_IEEEMODE);
1682            break;
1683        case AMDOP_INPUTS:
1684            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1685                            CALNOTE_ATI_INPUTS);
1686            break;
1687        case AMDOP_INPUTSAMPLERS:
1688            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1689                            CALNOTE_ATI_INPUT_SAMPLERS);
1690            break;
1691        case AMDOP_INTCONSTS:
1692            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1693                            CALNOTE_ATI_INT32CONSTS);
1694            break;
1695        case AMDOP_METADATA:
1696            AsmAmdPseudoOps::addMetadata(*this, stmtPlace, linePtr);
1697            break;
1698        case AMDOP_OUTPUTS:
1699            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1700                            CALNOTE_ATI_OUTPUTS);
1701            break;
1702        case AMDOP_PERSISTENTBUFFERS:
1703            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1704                            CALNOTE_ATI_PERSISTENT_BUFFERS);
1705            break;
1706        case AMDOP_PGMRSRC2:
1707            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PGMRSRC2);
1708            break;
1709        case AMDOP_PRINTFID:
1710            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PRINTFID);
1711            break;
1712        case AMDOP_PRIVATEID:
1713            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_PRIVATEID);
1714            break;
1715        case AMDOP_PROGINFO:
1716            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1717                            CALNOTE_ATI_PROGINFO);
1718            break;
1719        case AMDOP_SAMPLER:
1720            AsmAmdPseudoOps::doSampler(*this, stmtPlace, linePtr);
1721            break;
1722        case AMDOP_SCRATCHBUFFER:
1723            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
1724                                AMDCVAL_SCRATCHBUFFER);
1725            break;
1726        case AMDOP_SCRATCHBUFFERS:
1727            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1728                            CALNOTE_ATI_SCRATCH_BUFFERS);
1729            break;
1730        case AMDOP_SEGMENT:
1731            AsmAmdPseudoOps::doEntry(*this, stmtPlace, linePtr,
1732                    (1U<<CALNOTE_ATI_INT32CONSTS) | (1U<<CALNOTE_ATI_FLOAT32CONSTS) |
1733                    (1U<<CALNOTE_ATI_BOOL32CONSTS), "segment");
1734            break;
1735        case AMDOP_SGPRSNUM:
1736            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_SGPRSNUM);
1737            break;
1738        case AMDOP_SUBCONSTANTBUFFERS:
1739            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1740                            CALNOTE_ATI_SUB_CONSTANT_BUFFERS);
1741            break;
1742        case AMDOP_TGSIZE:
1743            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1744                            AMDCVAL_TGSIZE);
1745            break;
1746        case AMDOP_UAV:
1747            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1748                            CALNOTE_ATI_UAV);
1749            break;
1750        case AMDOP_UAVID:
1751            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_UAVID);
1752            break;
1753        case AMDOP_UAVMAILBOXSIZE:
1754            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1755                            CALNOTE_ATI_UAV_MAILBOX_SIZE);
1756            break;
1757        case AMDOP_UAVOPMASK:
1758            AsmAmdPseudoOps::addCALNote(*this, stmtPlace, linePtr,
1759                            CALNOTE_ATI_UAV_OP_MASK);
1760            break;
1761        case AMDOP_UAVPRIVATE:
1762            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_UAVPRIVATE);
1763            break;
1764        case AMDOP_USECONSTDATA:
1765            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1766                            AMDCVAL_USECONSTDATA);
1767            break;
1768        case AMDOP_USEPRINTF:
1769            AsmAmdPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
1770                            AMDCVAL_USEPRINTF);
1771            break;
1772        case AMDOP_USERDATA:
1773            AsmAmdPseudoOps::addUserData(*this, stmtPlace, linePtr);
1774            break;
1775        case AMDOP_VGPRSNUM:
1776            AsmAmdPseudoOps::setConfigValue(*this, stmtPlace, linePtr, AMDCVAL_VGPRSNUM);
1777            break;
1778        default:
1779            return false;
1780    }
1781    return true;
1782}
1783
1784bool AsmAmdHandler::prepareBinary()
1785{
1786    if (assembler.isaAssembler!=nullptr)
1787        saveCurrentAllocRegs(); // save last kernel allocated registers to kernel state
1788   
1789    output.is64Bit = assembler.is64Bit();
1790    output.deviceType = assembler.getDeviceType();
1791    /* initialize sections */
1792    const size_t sectionsNum = sections.size();
1793    const size_t kernelsNum = kernelStates.size();
1794    for (size_t i = 0; i < sectionsNum; i++)
1795    {
1796        const AsmSection& asmSection = assembler.sections[i];
1797        const Section& section = sections[i];
1798        const size_t sectionSize = asmSection.getSize();
1799        const cxbyte* sectionData = (!asmSection.content.empty()) ?
1800                asmSection.content.data() : (const cxbyte*)"";
1801        AmdKernelInput* kernel = (section.kernelId!=ASMKERN_GLOBAL) ?
1802                    &output.kernels[section.kernelId] : nullptr;
1803               
1804        switch(asmSection.type)
1805        {
1806            case AsmSectionType::CODE:
1807                kernel->codeSize = sectionSize;
1808                kernel->code = sectionData;
1809                break;
1810            case AsmSectionType::AMD_HEADER:
1811                kernel->headerSize = sectionSize;
1812                kernel->header = sectionData;
1813                break;
1814            case AsmSectionType::AMD_METADATA:
1815                kernel->metadataSize = sectionSize;
1816                kernel->metadata = (const char*)sectionData;
1817                break;
1818            case AsmSectionType::DATA:
1819                if (section.kernelId == ASMKERN_GLOBAL)
1820                {   // this is global data
1821                    if (sectionSize!=0)
1822                    {
1823                        output.globalDataSize = sectionSize;
1824                        output.globalData = sectionData;
1825                    }
1826                }
1827                else
1828                {   // this is kernel data
1829                    kernel->dataSize = sectionSize;
1830                    kernel->data = sectionData;
1831                }
1832                break;
1833            case AsmSectionType::AMD_CALNOTE:
1834            {
1835                CALNoteInput calNote;
1836                calNote.header.type = section.extraId;
1837                calNote.header.descSize = sectionSize;
1838                calNote.header.nameSize = 8;
1839                ::memcpy(calNote.header.name, "ATI CAL", 8);
1840                calNote.data = sectionData;
1841                kernel->calNotes.push_back(calNote);
1842                break;
1843            }
1844            case AsmSectionType::EXTRA_PROGBITS:
1845            case AsmSectionType::EXTRA_NOTE:
1846            case AsmSectionType::EXTRA_NOBITS:
1847            case AsmSectionType::EXTRA_SECTION:
1848            {
1849                uint32_t elfSectType =
1850                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
1851                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
1852                             SHT_PROGBITS;
1853                uint32_t elfSectFlags = 
1854                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
1855                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
1856                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
1857                if (section.kernelId == ASMKERN_GLOBAL)
1858                    output.extraSections.push_back({section.name, sectionSize, sectionData,
1859                            asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1860                            elfSectFlags, ELFSECTID_NULL, 0, 0 });
1861                else
1862                    kernel->extraSections.push_back({section.name, sectionSize, sectionData,
1863                            asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1864                            elfSectFlags, ELFSECTID_NULL, 0, 0 });
1865                break;
1866            }
1867            default: // ignore other sections
1868                break;
1869        }
1870    }
1871   
1872    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
1873    const cxuint maxSGPRsNumWithoutVCC = getGPUMaxRegistersNum(arch, REGTYPE_SGPR,
1874                REGCOUNT_NO_VCC);
1875    // set up number of the allocated SGPRs and VGPRs for kernel
1876    for (size_t i = 0; i < kernelsNum; i++)
1877    {
1878        if (!output.kernels[i].useConfig)
1879            continue;
1880        AmdKernelConfig& config = output.kernels[i].config;
1881        cxuint userSGPRsNum = 0;
1882        /* include userData sgprs */
1883        for (cxuint i = 0; i < config.userDatas.size(); i++)
1884            userSGPRsNum = std::max(userSGPRsNum,
1885                        config.userDatas[i].regStart+config.userDatas[i].regSize);
1886       
1887        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
1888                ((config.pgmRSRC2>>7)&7);
1889        cxuint minRegsNum[2];
1890        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
1891                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
1892                   ((config.scratchBufferSize!=0) ? GPUSETUP_SCRATCH_EN : 0), minRegsNum);
1893       
1894        if (config.usedSGPRsNum==BINGEN_DEFAULT)
1895            config.usedSGPRsNum = std::min(maxSGPRsNumWithoutVCC,
1896                std::max(minRegsNum[0], kernelStates[i]->allocRegs[0]));
1897        if (config.usedVGPRsNum==BINGEN_DEFAULT)
1898            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i]->allocRegs[1]);
1899    }
1900   
1901    /* put extra symbols */
1902    if (assembler.flags & ASM_FORCE_ADD_SYMBOLS)
1903        for (const AsmSymbolEntry& symEntry: assembler.symbolMap)
1904        {
1905            if (!symEntry.second.hasValue ||
1906                ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
1907                continue; // unresolved or local
1908            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
1909                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
1910            if (binSectId==ELFSECTID_UNDEF)
1911                continue; // no section
1912           
1913            const BinSymbol binSym = { symEntry.first, symEntry.second.value,
1914                        symEntry.second.size, binSectId, false, symEntry.second.info,
1915                        symEntry.second.other };
1916           
1917            if (symEntry.second.sectionId == ASMSECT_ABS ||
1918                sections[symEntry.second.sectionId].kernelId == ASMKERN_GLOBAL)
1919                output.extraSymbols.push_back(std::move(binSym));
1920            else // to kernel extra symbols
1921                output.kernels[sections[symEntry.second.sectionId].kernelId].extraSymbols
1922                            .push_back(std::move(binSym));
1923        }
1924    // driver version setup
1925    if (output.driverVersion==0 && output.driverInfo.empty() &&
1926        (assembler.flags&ASM_TESTRUN)==0)
1927    {
1928        if (assembler.driverVersion==0) // just detect driver version
1929            output.driverVersion = detectAmdDriverVersion();
1930        else // from assembler setup
1931            output.driverVersion = assembler.driverVersion;
1932    }
1933    return true;
1934}
1935
1936void AsmAmdHandler::writeBinary(std::ostream& os) const
1937{
1938    AmdGPUBinGenerator binGenerator(&output);
1939    binGenerator.generate(os);
1940}
1941
1942void AsmAmdHandler::writeBinary(Array<cxbyte>& array) const
1943{
1944    AmdGPUBinGenerator binGenerator(&output);
1945    binGenerator.generate(array);
1946}
Note: See TracBrowser for help on using the repository browser.