source: CLRX/CLRadeonExtender/trunk/amdasm/AsmGalliumFormat.cpp @ 2377

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

CLRadeonExtender: Asm: Allow to define empty dimensions list in configuration. Disasm: Print empty dimensions in configuration.

File size: 42.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 <cstring>
22#include <string>
23#include <vector>
24#include <utility>
25#include <algorithm>
26#include <CLRX/utils/Utilities.h>
27#include <CLRX/amdasm/Assembler.h>
28#include "AsmInternals.h"
29
30using namespace CLRX;
31
32static const char* galliumPseudoOpNamesTbl[] =
33{
34    "arg", "args", "config",
35    "debugmode", "dims", "dx10clamp",
36    "entry", "exceptions", "floatmode",
37    "globaldata", "ieeemode",
38    "kcode", "kcodeend",
39    "localsize", "pgmrsrc1", "pgmrsrc2", "priority",
40    "privmode", "proginfo",
41    "scratchbuffer", "sgprsnum", "tgsize",
42    "userdatanum", "vgprsnum"
43};
44
45enum
46{
47    GALLIUMOP_ARG = 0, GALLIUMOP_ARGS, GALLIUMOP_CONFIG,
48    GALLIUMOP_DEBUGMODE, GALLIUMOP_DIMS, GALLIUMOP_DX10CLAMP,
49    GALLIUMOP_ENTRY, GALLIUMOP_EXCEPTIONS, GALLIUMOP_FLOATMODE,
50    GALLIUMOP_GLOBALDATA, GALLIUMOP_IEEEMODE,
51    GALLIUMOP_KCODE, GALLIUMOP_KCODEEND,
52    GALLIUMOP_LOCALSIZE, GALLIUMOP_PGMRSRC1, GALLIUMOP_PGMRSRC2, GALLIUMOP_PRIORITY,
53    GALLIUMOP_PRIVMODE, GALLIUMOP_PROGINFO,
54    GALLIUMOP_SCRATCHBUFFER, GALLIUMOP_SGPRSNUM, GALLIUMOP_TGSIZE,
55    GALLIUMOP_USERDATANUM, GALLIUMOP_VGPRSNUM
56};
57
58/*
59 * GalliumCompute format handler
60 */
61
62AsmGalliumHandler::AsmGalliumHandler(Assembler& assembler): AsmFormatHandler(assembler),
63             output{}, codeSection(0), dataSection(ASMSECT_NONE),
64             commentSection(ASMSECT_NONE), extraSectionCount(0)
65{
66    assembler.currentKernel = ASMKERN_GLOBAL;
67    assembler.currentSection = 0;
68    sections.push_back({ ASMKERN_GLOBAL, AsmSectionType::CODE,
69                ELFSECTID_TEXT, ".text" });
70    inside = Inside::MAINLAYOUT;
71    currentKcodeKernel = ASMKERN_GLOBAL;
72    savedSection = 0;
73}
74
75cxuint AsmGalliumHandler::addKernel(const char* kernelName)
76{
77    cxuint thisKernel = output.kernels.size();
78    cxuint thisSection = sections.size();
79    output.addEmptyKernel(kernelName);
80    /// add kernel config section
81    sections.push_back({ thisKernel, AsmSectionType::CONFIG, ELFSECTID_UNDEF, nullptr });
82    kernelStates.push_back({ thisSection, false, 0 });
83   
84    if (assembler.currentKernel == ASMKERN_GLOBAL)
85        savedSection = assembler.currentSection;
86   
87    assembler.currentKernel = thisKernel;
88    assembler.currentSection = thisSection;
89    inside = Inside::MAINLAYOUT;
90    return thisKernel;
91}
92
93cxuint AsmGalliumHandler::addSection(const char* sectionName, cxuint kernelId)
94{
95    const cxuint thisSection = sections.size();
96    Section section;
97    section.kernelId = ASMKERN_GLOBAL;  // we ignore input kernelId, we go to main
98   
99    if (::strcmp(sectionName, ".rodata") == 0) // data
100    {
101        if (dataSection!=ASMSECT_NONE)
102            throw AsmFormatException("Only section '.rodata' can be in binary");
103        dataSection = thisSection;
104        section.type = AsmSectionType::DATA;
105        section.elfBinSectId = ELFSECTID_RODATA;
106        section.name = ".rodata"; // set static name (available by whole lifecycle)
107    }
108    else if (::strcmp(sectionName, ".text") == 0) // code
109    {
110        if (codeSection!=ASMSECT_NONE)
111            throw AsmFormatException("Only one section '.text' can be in binary");
112        codeSection = thisSection;
113        section.type = AsmSectionType::CODE;
114        section.elfBinSectId = ELFSECTID_TEXT;
115        section.name = ".text"; // set static name (available by whole lifecycle)
116    }
117    else if (::strcmp(sectionName, ".comment") == 0) // comment
118    {
119        if (commentSection!=ASMSECT_NONE)
120            throw AsmFormatException("Only one section '.comment' can be in binary");
121        commentSection = thisSection;
122        section.type = AsmSectionType::GALLIUM_COMMENT;
123        section.elfBinSectId = ELFSECTID_COMMENT;
124        section.name = ".comment"; // set static name (available by whole lifecycle)
125    }
126    else
127    {
128        auto out = extraSectionMap.insert(std::make_pair(CString(sectionName),
129                    thisSection));
130        if (!out.second)
131            throw AsmFormatException("Section already exists");
132        section.type = AsmSectionType::EXTRA_SECTION;
133        section.elfBinSectId = extraSectionCount++;
134        /// referfence entry is available and unchangeable by whole lifecycle of section map
135        section.name = out.first->first.c_str();
136    }
137    sections.push_back(section);
138   
139    assembler.currentKernel = ASMKERN_GLOBAL;
140    assembler.currentSection = thisSection;
141    inside = Inside::MAINLAYOUT;
142    return thisSection;
143}
144
145cxuint AsmGalliumHandler::getSectionId(const char* sectionName) const
146{
147    if (::strcmp(sectionName, ".rodata") == 0) // data
148        return dataSection;
149    else if (::strcmp(sectionName, ".text") == 0) // code
150        return codeSection;
151    else if (::strcmp(sectionName, ".comment") == 0) // comment
152        return commentSection;
153    else
154    {
155        SectionMap::const_iterator it = extraSectionMap.find(sectionName);
156        if (it != extraSectionMap.end())
157            return it->second;
158    }
159    return ASMSECT_NONE;
160}
161
162void AsmGalliumHandler::setCurrentKernel(cxuint kernel)
163{   // set kernel and their default section
164    if (kernel != ASMKERN_GLOBAL && kernel >= kernelStates.size())
165        throw AsmFormatException("KernelId out of range");
166   
167    if (assembler.currentKernel == ASMKERN_GLOBAL)
168        savedSection = assembler.currentSection;
169   
170    assembler.currentKernel = kernel;
171    if (kernel != ASMKERN_GLOBAL)
172        assembler.currentSection = kernelStates[kernel].defaultSection;
173    else // default main section
174        assembler.currentSection = savedSection;
175    inside = Inside::MAINLAYOUT;
176}
177
178void AsmGalliumHandler::setCurrentSection(cxuint sectionId)
179{
180    if (sectionId >= sections.size())
181        throw AsmFormatException("SectionId out of range");
182   
183    if (assembler.currentKernel == ASMKERN_GLOBAL)
184        savedSection = assembler.currentSection;
185   
186    assembler.currentSection = sectionId;
187    assembler.currentKernel = sections[sectionId].kernelId;
188    inside = Inside::MAINLAYOUT;
189}
190
191AsmFormatHandler::SectionInfo AsmGalliumHandler::getSectionInfo(cxuint sectionId) const
192{
193    if (sectionId >= sections.size())
194        throw AsmFormatException("Section doesn't exists");
195   
196    AsmFormatHandler::SectionInfo info;
197    info.type = sections[sectionId].type;
198    info.flags = 0;
199    if (info.type == AsmSectionType::CODE)
200        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE;
201    else if (info.type != AsmSectionType::CONFIG)
202        info.flags = ASMSECT_ADDRESSABLE | ASMSECT_WRITEABLE | ASMSECT_ABS_ADDRESSABLE;
203   
204    info.name = sections[sectionId].name;
205    return info;
206}
207
208// check whether label is kernel label and restore register allocation to this kernel
209void AsmGalliumHandler::handleLabel(const CString& label)
210{
211    if (assembler.sections[assembler.currentSection].type != AsmSectionType::CODE)
212        return;
213    auto kit = assembler.kernelMap.find(label);
214    if (kit == assembler.kernelMap.end())
215        return;
216    if (!kcodeSelection.empty())
217        return; // do not change if inside kcode
218    // save other state
219    saveKcodeCurrentAllocRegs();
220    // restore this state
221    currentKcodeKernel = kit->second;
222    restoreKcodeCurrentAllocRegs();
223}
224
225void AsmGalliumHandler::restoreKcodeCurrentAllocRegs()
226{
227    if (currentKcodeKernel != ASMKERN_GLOBAL)
228    {
229        Kernel& newKernel = kernelStates[currentKcodeKernel];
230        assembler.isaAssembler->setAllocatedRegisters(newKernel.allocRegs,
231                            newKernel.allocRegFlags);
232    }
233}
234
235void AsmGalliumHandler::saveKcodeCurrentAllocRegs()
236{
237    if (currentKcodeKernel != ASMKERN_GLOBAL)
238    {   // save other state
239        size_t regTypesNum;
240        Kernel& oldKernel = kernelStates[currentKcodeKernel];
241        const cxuint* regs = assembler.isaAssembler->getAllocatedRegisters(
242                            regTypesNum, oldKernel.allocRegFlags);
243        std::copy(regs, regs+2, oldKernel.allocRegs);
244    }
245}
246
247namespace CLRX
248{
249
250bool AsmGalliumPseudoOps::checkPseudoOpName(const CString& string)
251{
252    if (string.empty() || string[0] != '.')
253        return false;
254    const size_t pseudoOp = binaryFind(galliumPseudoOpNamesTbl, galliumPseudoOpNamesTbl +
255                sizeof(galliumPseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
256               CStringLess()) - galliumPseudoOpNamesTbl;
257    return pseudoOp < sizeof(galliumPseudoOpNamesTbl)/sizeof(char*);
258}
259
260void AsmGalliumPseudoOps::doConfig(AsmGalliumHandler& handler, const char* pseudoOpPlace,
261                      const char* linePtr)
262{
263    Assembler& asmr = handler.assembler;
264    const char* end = asmr.line + asmr.lineSize;
265    if (handler.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
266    {
267        asmr.printError(pseudoOpPlace, "Configuration outside kernel definition");
268        return;
269    }
270    if (handler.kernelStates[asmr.currentKernel].hasProgInfo)
271    {
272        asmr.printError(pseudoOpPlace,
273                "Configuration can't be defined if progInfo was defined");
274        return;
275    }
276    skipSpacesToEnd(linePtr, end);
277    if (!checkGarbagesAtEnd(asmr, linePtr))
278        return;
279   
280    handler.inside = AsmGalliumHandler::Inside::CONFIG;
281    handler.output.kernels[asmr.currentKernel].useConfig = true;
282}
283
284void AsmGalliumPseudoOps::doGlobalData(AsmGalliumHandler& handler,
285                   const char* pseudoOpPlace, const char* linePtr)
286{
287    Assembler& asmr = handler.assembler;
288    const char* end = asmr.line + asmr.lineSize;
289    skipSpacesToEnd(linePtr, end);
290    if (!checkGarbagesAtEnd(asmr, linePtr))
291        return;
292   
293    asmr.goToSection(pseudoOpPlace, ".rodata");
294}
295
296void AsmGalliumPseudoOps::setDimensions(AsmGalliumHandler& handler,
297                    const char* pseudoOpPlace, const char* linePtr)
298{
299    Assembler& asmr = handler.assembler;
300    const char* end = asmr.line + asmr.lineSize;
301    if (asmr.currentKernel==ASMKERN_GLOBAL ||
302        handler.inside != AsmGalliumHandler::Inside::CONFIG)
303    {
304        asmr.printError(pseudoOpPlace, "Illegal place of configuration pseudo-op");
305        return;
306    }
307    skipSpacesToEnd(linePtr, end);
308    const char* dimPlace = linePtr;
309    char buf[10];
310    cxuint dimMask = 0;
311    if (getNameArg(asmr, 10, buf, linePtr, "dimension set", false))
312    {
313        toLowerString(buf);
314        for (cxuint i = 0; buf[i]!=0; i++)
315            if (buf[i]=='x')
316                dimMask |= 1;
317            else if (buf[i]=='y')
318                dimMask |= 2;
319            else if (buf[i]=='z')
320                dimMask |= 4;
321            else
322            {
323                asmr.printError(dimPlace, "Unknown dimension type");
324                return;
325            }
326    }
327    else // error
328        return;
329    if (!checkGarbagesAtEnd(asmr, linePtr))
330        return;
331    handler.output.kernels[asmr.currentKernel].config.dimMask = dimMask;
332}
333
334void AsmGalliumPseudoOps::setConfigValue(AsmGalliumHandler& handler,
335         const char* pseudoOpPlace, const char* linePtr, GalliumConfigValueTarget target)
336{
337    Assembler& asmr = handler.assembler;
338    const char* end = asmr.line + asmr.lineSize;
339   
340    if (asmr.currentKernel==ASMKERN_GLOBAL ||
341        handler.inside != AsmGalliumHandler::Inside::CONFIG)
342    {
343        asmr.printError(pseudoOpPlace, "Illegal place of configuration pseudo-op");
344        return;
345    }
346   
347    skipSpacesToEnd(linePtr, end);
348    const char* valuePlace = linePtr;
349    uint64_t value = BINGEN_NOTSUPPLIED;
350    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
351    /* ranges checking */
352    if (good)
353    {
354        switch(target)
355        {
356            case GALLIUMCVAL_SGPRSNUM:
357            {
358                const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
359                            asmr.deviceType);
360                cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
361                if (value > maxSGPRsNum)
362                {
363                    char buf[64];
364                    snprintf(buf, 64, "Used SGPRs number out of range (0-%u)", maxSGPRsNum);
365                    asmr.printError(valuePlace, buf);
366                    good = false;
367                }
368                break;
369            }
370            case GALLIUMCVAL_VGPRSNUM:
371            {
372                const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
373                            asmr.deviceType);
374                cxuint maxVGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
375                if (value > maxVGPRsNum)
376                {
377                    char buf[64];
378                    snprintf(buf, 64, "Used VGPRs number out of range (0-%u)", maxVGPRsNum);
379                    asmr.printError(valuePlace, buf);
380                    good = false;
381                }
382                break;
383            }
384            case GALLIUMCVAL_EXCEPTIONS:
385                asmr.printWarningForRange(7, value,
386                                  asmr.getSourcePos(valuePlace), WS_UNSIGNED);
387                value &= 0x7f;
388                break;
389            case GALLIUMCVAL_FLOATMODE:
390                asmr.printWarningForRange(8, value,
391                                  asmr.getSourcePos(valuePlace), WS_UNSIGNED);
392                value &= 0xff;
393                break;
394            case GALLIUMCVAL_PRIORITY:
395                asmr.printWarningForRange(2, value,
396                                  asmr.getSourcePos(valuePlace), WS_UNSIGNED);
397                value &= 3;
398                break;
399            case GALLIUMCVAL_LOCALSIZE:
400            {
401                const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
402                            asmr.deviceType);
403                const cxuint maxLocalSize = getGPUMaxLocalSize(arch);
404                if (value > maxLocalSize)
405                {
406                    char buf[64];
407                    snprintf(buf, 64, "LocalSize out of range (0-%u)", maxLocalSize);
408                    asmr.printError(valuePlace, buf);
409                    good = false;
410                }
411                break;
412            }
413            case GALLIUMCVAL_USERDATANUM:
414                if (value > 16)
415                {
416                    asmr.printError(valuePlace, "UserDataNum out of range (0-16)");
417                    good = false;
418                }
419                break;
420            default:
421                break;
422        }
423    }
424   
425    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
426        return;
427   
428    GalliumKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
429    // set value
430    switch(target)
431    {
432        case GALLIUMCVAL_SGPRSNUM:
433            config.usedSGPRsNum = value;
434            break;
435        case GALLIUMCVAL_VGPRSNUM:
436            config.usedVGPRsNum = value;
437            break;
438        case GALLIUMCVAL_PGMRSRC1:
439            config.pgmRSRC1 = value;
440            break;
441        case GALLIUMCVAL_PGMRSRC2:
442            config.pgmRSRC2 = value;
443            break;
444        case GALLIUMCVAL_FLOATMODE:
445            config.floatMode = value;
446            break;
447        case GALLIUMCVAL_LOCALSIZE:
448            config.localSize = value;
449            break;
450        case GALLIUMCVAL_SCRATCHBUFFER:
451            config.scratchBufferSize = value;
452            break;
453        case GALLIUMCVAL_PRIORITY:
454            config.priority = value;
455            break;
456        case GALLIUMCVAL_USERDATANUM:
457            config.userDataNum = value;
458            break;
459        case GALLIUMCVAL_EXCEPTIONS:
460            config.exceptions = value;
461            break;
462        default:
463            break;
464    }
465}
466
467void AsmGalliumPseudoOps::setConfigBoolValue(AsmGalliumHandler& handler,
468         const char* pseudoOpPlace, const char* linePtr, GalliumConfigValueTarget target)
469{
470    Assembler& asmr = handler.assembler;
471   
472    if (asmr.currentKernel==ASMKERN_GLOBAL ||
473        handler.inside != AsmGalliumHandler::Inside::CONFIG)
474    {
475        asmr.printError(pseudoOpPlace, "Illegal place of configuration pseudo-op");
476        return;
477    }
478    if (!checkGarbagesAtEnd(asmr, linePtr))
479        return;
480    GalliumKernelConfig& config = handler.output.kernels[asmr.currentKernel].config;
481    switch(target)
482    {
483        case GALLIUMCVAL_DEBUGMODE:
484            config.debugMode = true;
485            break;
486        case GALLIUMCVAL_DX10CLAMP:
487            config.dx10Clamp = true;
488            break;
489        case GALLIUMCVAL_IEEEMODE:
490            config.ieeeMode = true;
491            break;
492        case GALLIUMCVAL_PRIVMODE:
493            config.privilegedMode = true;
494            break;
495        case GALLIUMCVAL_TGSIZE:
496            config.tgSize = true;
497            break;
498        default:
499            break;
500    }
501}
502
503void AsmGalliumPseudoOps::doArgs(AsmGalliumHandler& handler,
504               const char* pseudoOpPlace, const char* linePtr)
505{
506    Assembler& asmr = handler.assembler;
507    const char* end = asmr.line + asmr.lineSize;
508    if (handler.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
509    {
510        asmr.printError(pseudoOpPlace, "Arguments outside kernel definition");
511        return;
512    }
513    skipSpacesToEnd(linePtr, end);
514    if (!checkGarbagesAtEnd(asmr, linePtr))
515        return;
516   
517    handler.inside = AsmGalliumHandler::Inside::ARGS;
518}
519
520static const std::pair<const char*, GalliumArgType> galliumArgTypesMap[9] =
521{
522    { "constant", GalliumArgType::CONSTANT },
523    { "global", GalliumArgType::GLOBAL },
524    { "image2d_rd", GalliumArgType::IMAGE2D_RDONLY },
525    { "image2d_wr", GalliumArgType::IMAGE2D_WRONLY },
526    { "image3d_rd", GalliumArgType::IMAGE3D_RDONLY },
527    { "image3d_wr", GalliumArgType::IMAGE3D_WRONLY },
528    { "local", GalliumArgType::LOCAL },
529    { "sampler", GalliumArgType::SAMPLER },
530    { "scalar", GalliumArgType::SCALAR }
531};
532
533static const std::pair<const char*, cxuint> galliumArgSemanticsMap[5] =
534{
535    { "general", cxuint(GalliumArgSemantic::GENERAL) },
536    { "griddim", cxuint(GalliumArgSemantic::GRID_DIMENSION) },
537    { "gridoffset", cxuint(GalliumArgSemantic::GRID_OFFSET) },
538    { "imgformat", cxuint(GalliumArgSemantic::IMAGE_FORMAT) },
539    { "imgsize", cxuint(GalliumArgSemantic::IMAGE_SIZE) },
540};
541
542void AsmGalliumPseudoOps::doArg(AsmGalliumHandler& handler, const char* pseudoOpPlace,
543                      const char* linePtr)
544{
545    Assembler& asmr = handler.assembler;
546    const char* end = asmr.line + asmr.lineSize;
547   
548    if (handler.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
549    {
550        asmr.printError(pseudoOpPlace, "Argument definition outside kernel configuration");
551        return;
552    }
553    if (handler.inside != AsmGalliumHandler::Inside::ARGS)
554    {
555        asmr.printError(pseudoOpPlace, "Argument definition outside arguments list");
556        return;
557    }
558   
559    skipSpacesToEnd(linePtr, end);
560    char name[20];
561    bool good = true;
562    const char* nameStringPlace = linePtr;
563    GalliumArgType argType = GalliumArgType::GLOBAL;
564   
565    GalliumArgSemantic argSemantic = GalliumArgSemantic::GENERAL;
566    bool semanticDefined = false;
567    if (getNameArg(asmr, 20, name, linePtr, "argument type"))
568    {
569        toLowerString(name);
570        if (::strcmp(name, "griddim")==0)
571        {   // shortcur for grid dimension
572            argSemantic = GalliumArgSemantic::GRID_DIMENSION;
573            argType = GalliumArgType::SCALAR;
574            semanticDefined = true;
575        }
576        else if (::strcmp(name, "gridoffset")==0)
577        {   // shortcut for grid dimension
578            argSemantic = GalliumArgSemantic::GRID_OFFSET;
579            argType = GalliumArgType::SCALAR;
580            semanticDefined = true;
581        }
582        else
583        {
584            cxuint index = binaryMapFind(galliumArgTypesMap, galliumArgTypesMap + 9,
585                         name, CStringLess()) - galliumArgTypesMap;
586            if (index != 9) // end of this map
587                argType = galliumArgTypesMap[index].second;
588            else
589            {
590                asmr.printError(nameStringPlace, "Unknown argument type");
591                good = false;
592            }
593        }
594    }
595    else
596        good = false;
597   
598    // parse rest of arguments
599    if (!skipRequiredComma(asmr, linePtr))
600        return;
601    skipSpacesToEnd(linePtr, end);
602    const char* sizeStrPlace = linePtr;
603    uint64_t size = 4;
604    good &= getAbsoluteValueArg(asmr, size, linePtr, true);
605   
606    if (size > UINT32_MAX || size == 0)
607        asmr.printWarning(sizeStrPlace, "Size of argument out of range");
608   
609    uint64_t targetSize = (size+3ULL)&~3ULL;
610    uint64_t targetAlign = (size!=0) ? 1ULL<<(63-CLZ64(targetSize)) : 1;
611    if (targetSize > targetAlign)
612        targetAlign <<= 1;
613    bool sext = false;
614   
615    bool haveComma;
616    if (!skipComma(asmr, haveComma, linePtr))
617        return;
618    if (haveComma)
619    {
620        skipSpacesToEnd(linePtr, end);
621        const char* targetSizePlace = linePtr;
622        if (getAbsoluteValueArg(asmr, targetSize, linePtr, false))
623        {
624            if (targetSize > UINT32_MAX || targetSize == 0)
625                asmr.printWarning(targetSizePlace, "Target size of argument out of range");
626        }
627        else
628            good = false;
629       
630        if (!skipComma(asmr, haveComma, linePtr))
631            return;
632        if (haveComma)
633        {
634            skipSpacesToEnd(linePtr, end);
635            const char* targetAlignPlace = linePtr;
636            if (getAbsoluteValueArg(asmr, targetAlign, linePtr, false))
637            {
638                if (targetAlign > UINT32_MAX || targetAlign == 0)
639                    asmr.printWarning(targetAlignPlace,
640                                      "Target alignment of argument out of range");
641                if (targetAlign != (1ULL<<(63-CLZ64(targetAlign))))
642                {
643                    asmr.printError(targetAlignPlace, "Target alignment is not power of 2");
644                    good = false;
645                }
646            }
647            else
648                good = false;
649           
650            if (!skipComma(asmr, haveComma, linePtr))
651                return;
652            if (haveComma)
653            {
654                skipSpacesToEnd(linePtr, end);
655                const char* numExtPlace = linePtr;
656                if (getNameArg(asmr, 5, name, linePtr, "numeric extension", false))
657                {
658                    toLowerString(name);
659                    if (::strcmp(name, "sext")==0)
660                        sext = true;
661                    else if (::strcmp(name, "zext")!=0 && *name!=0)
662                    {
663                        asmr.printError(numExtPlace, "Unknown numeric extension");
664                        good = false;
665                    }
666                }
667                else
668                    good = false;
669               
670                if (!semanticDefined)
671                {   /// if semantic has not been defined in the first argument
672                    if (!skipComma(asmr, haveComma, linePtr))
673                        return;
674                    if (haveComma)
675                    {
676                        cxuint semantic;
677                        if (getEnumeration(asmr, linePtr, "argument semantic", 5,
678                                    galliumArgSemanticsMap, semantic))
679                            argSemantic = GalliumArgSemantic(semantic);
680                        else
681                            good = false;
682                    }
683                }
684            }
685        }
686    }
687   
688    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
689        return;
690   
691    // put this definition to argument list
692    handler.output.kernels[asmr.currentKernel].argInfos.push_back(
693        { argType, sext, argSemantic, uint32_t(size),
694            uint32_t(targetSize), uint32_t(targetAlign) });
695}
696
697void AsmGalliumPseudoOps::doProgInfo(AsmGalliumHandler& handler,
698                 const char* pseudoOpPlace, const char* linePtr)
699{
700    Assembler& asmr = handler.assembler;
701    const char* end = asmr.line + asmr.lineSize;
702    if (handler.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
703    {
704        asmr.printError(pseudoOpPlace, "ProgInfo outside kernel definition");
705        return;
706    }
707    if (handler.output.kernels[asmr.currentKernel].useConfig)
708    {
709        asmr.printError(pseudoOpPlace,
710                "ProgInfo can't be defined if configuration was exists");
711        return;
712    }
713    skipSpacesToEnd(linePtr, end);
714    if (!checkGarbagesAtEnd(asmr, linePtr))
715        return;
716   
717    handler.inside = AsmGalliumHandler::Inside::PROGINFO;
718    handler.kernelStates[asmr.currentKernel].hasProgInfo = true;
719}
720
721void AsmGalliumPseudoOps::doEntry(AsmGalliumHandler& handler,
722                    const char* pseudoOpPlace, const char* linePtr)
723{
724    Assembler& asmr = handler.assembler;
725    const char* end = asmr.line + asmr.lineSize;
726   
727    if (handler.sections[asmr.currentSection].type != AsmSectionType::CONFIG)
728    {
729        asmr.printError(pseudoOpPlace, "ProgInfo entry outside kernel configuration");
730        return;
731    }
732    if (handler.inside != AsmGalliumHandler::Inside::PROGINFO)
733    {
734        asmr.printError(pseudoOpPlace, "ProgInfo entry definition outside ProgInfo");
735        return;
736    }
737   
738    skipSpacesToEnd(linePtr, end);
739    const char* addrPlace = linePtr;
740    uint64_t entryAddr;
741    bool good = true;
742    if (getAbsoluteValueArg(asmr, entryAddr, linePtr, true))
743        asmr.printWarningForRange(32, entryAddr, asmr.getSourcePos(addrPlace),
744                              WS_UNSIGNED);
745    else
746        good = false;
747    if (!skipRequiredComma(asmr, linePtr))
748        return;
749   
750    skipSpacesToEnd(linePtr, end);
751    const char* entryValPlace = linePtr;
752    uint64_t entryVal;
753    if (getAbsoluteValueArg(asmr, entryVal, linePtr, true))
754        asmr.printWarningForRange(32, entryVal, asmr.getSourcePos(entryValPlace));
755    else
756        good = false;
757   
758    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
759        return;
760   
761    // do operation
762    AsmGalliumHandler::Kernel& kstate = handler.kernelStates[asmr.currentKernel];
763    kstate.hasProgInfo = true;
764    if (kstate.progInfoEntries == 3)
765    {
766        asmr.printError(pseudoOpPlace, "Maximum 3 entries can be in ProgInfo");
767        return;
768    }
769    GalliumProgInfoEntry& pentry = handler.output.kernels[asmr.currentKernel]
770            .progInfo[kstate.progInfoEntries++];
771    pentry.address = entryAddr;
772    pentry.value = entryVal;
773}
774
775/* update kernel code selection, join all regallocation and store to
776 * current kernel regalloc */
777void AsmGalliumPseudoOps::updateKCodeSel(AsmGalliumHandler& handler,
778          const std::vector<cxuint>& oldset)
779{
780    Assembler& asmr = handler.assembler;
781    // old elements - join current regstate with all them
782    size_t regTypesNum;
783    for (auto it = oldset.begin(); it != oldset.end(); ++it)
784    {
785        Flags curAllocRegFlags;
786        const cxuint* curAllocRegs = asmr.isaAssembler->getAllocatedRegisters(regTypesNum,
787                               curAllocRegFlags);
788        cxuint newAllocRegs[2];
789        AsmGalliumHandler::Kernel& kernel = handler.kernelStates[*it];
790        newAllocRegs[0] = std::max(curAllocRegs[0], kernel.allocRegs[0]);
791        newAllocRegs[1] = std::max(curAllocRegs[1], kernel.allocRegs[1]);
792        kernel.allocRegFlags |= curAllocRegFlags;
793        std::copy(newAllocRegs, newAllocRegs+2, kernel.allocRegs);
794    }
795    asmr.isaAssembler->setAllocatedRegisters();
796}
797
798void AsmGalliumPseudoOps::doKCode(AsmGalliumHandler& handler, const char* pseudoOpPlace,
799                      const char* linePtr)
800{
801    Assembler& asmr = handler.assembler;
802    const char* end = asmr.line + asmr.lineSize;
803    bool good = true;
804    skipSpacesToEnd(linePtr, end);
805    if (linePtr==end)
806        return;
807    std::unordered_set<cxuint> newSel(handler.kcodeSelection.begin(),
808                          handler.kcodeSelection.end());
809    do {
810        CString kname;
811        const char* knamePlace = linePtr;
812        skipSpacesToEnd(linePtr, end);
813        bool removeKernel = false;
814        if (linePtr!=end && *linePtr=='-')
815        {   // '-' - remove this kernel from current kernel selection
816            removeKernel = true;
817            linePtr++;
818        }
819        else if (linePtr!=end && *linePtr=='+')
820        {
821            linePtr++;
822            skipSpacesToEnd(linePtr, end);
823            if (linePtr==end)
824            {   // add all kernels
825                for (cxuint k = 0; k < handler.kernelStates.size(); k++)
826                    newSel.insert(k);
827                break;
828            }
829        }
830       
831        if (!getNameArg(asmr, kname, linePtr, "kernel"))
832        { good = false; continue; }
833        auto kit = asmr.kernelMap.find(kname);
834        if (kit == asmr.kernelMap.end())
835        {
836            asmr.printError(knamePlace, "Kernel not found");
837            continue;
838        }
839        if (!removeKernel)
840            newSel.insert(kit->second);
841        else // remove kernel
842            newSel.erase(kit->second);
843    } while (skipCommaForMultipleArgs(asmr, linePtr));
844   
845    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
846        return;
847   
848    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
849    {
850        asmr.printError(pseudoOpPlace, "KCode outside code");
851        return;
852    }
853    if (handler.kcodeSelStack.empty())
854        handler.saveKcodeCurrentAllocRegs();
855    // push to stack
856    handler.kcodeSelStack.push(handler.kcodeSelection);
857    // set current sel
858    handler.kcodeSelection.assign(newSel.begin(), newSel.end());
859   
860    std::sort(handler.kcodeSelection.begin(), handler.kcodeSelection.end());
861    updateKCodeSel(handler, handler.kcodeSelStack.top());
862}
863
864void AsmGalliumPseudoOps::doKCodeEnd(AsmGalliumHandler& handler, const char* pseudoOpPlace,
865                  const char* linePtr)
866{
867    Assembler& asmr = handler.assembler;
868    if (handler.sections[asmr.currentSection].type != AsmSectionType::CODE)
869    {
870        asmr.printError(pseudoOpPlace, "KCodeEnd outside code");
871        return;
872    }
873    if (handler.kcodeSelStack.empty())
874    {
875        asmr.printError(pseudoOpPlace, "'.kcodeend' without '.kcode'");
876        return;
877    }
878    updateKCodeSel(handler, handler.kcodeSelection);
879    handler.kcodeSelection = handler.kcodeSelStack.top();
880    handler.kcodeSelStack.pop();
881    if (handler.kcodeSelStack.empty())
882        handler.restoreKcodeCurrentAllocRegs();
883}
884
885}
886
887bool AsmGalliumHandler::parsePseudoOp(const CString& firstName,
888           const char* stmtPlace, const char* linePtr)
889{
890    const size_t pseudoOp = binaryFind(galliumPseudoOpNamesTbl, galliumPseudoOpNamesTbl +
891                    sizeof(galliumPseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
892                   CStringLess()) - galliumPseudoOpNamesTbl;
893   
894    switch(pseudoOp)
895    {
896        case GALLIUMOP_ARG:
897            AsmGalliumPseudoOps::doArg(*this, stmtPlace, linePtr);
898            break;
899        case GALLIUMOP_ARGS:
900            AsmGalliumPseudoOps::doArgs(*this, stmtPlace, linePtr);
901            break;
902        case GALLIUMOP_CONFIG:
903            AsmGalliumPseudoOps::doConfig(*this, stmtPlace, linePtr);
904            break;
905        case GALLIUMOP_DEBUGMODE:
906            AsmGalliumPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
907                                GALLIUMCVAL_DEBUGMODE);
908            break;
909        case GALLIUMOP_DIMS:
910            AsmGalliumPseudoOps::setDimensions(*this, stmtPlace, linePtr);
911            break;
912        case GALLIUMOP_DX10CLAMP:
913            AsmGalliumPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
914                                GALLIUMCVAL_DX10CLAMP);
915            break;
916        case GALLIUMOP_ENTRY:
917            AsmGalliumPseudoOps::doEntry(*this, stmtPlace, linePtr);
918            break;
919        case GALLIUMOP_EXCEPTIONS:
920            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
921                                    GALLIUMCVAL_EXCEPTIONS);
922            break;
923        case GALLIUMOP_FLOATMODE:
924            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
925                                    GALLIUMCVAL_FLOATMODE);
926            break;
927        case GALLIUMOP_GLOBALDATA:
928            AsmGalliumPseudoOps::doGlobalData(*this, stmtPlace, linePtr);
929            break;
930        case GALLIUMOP_IEEEMODE:
931            AsmGalliumPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
932                                    GALLIUMCVAL_IEEEMODE);
933            break;
934        case GALLIUMOP_KCODE:
935            AsmGalliumPseudoOps::doKCode(*this, stmtPlace, linePtr);
936            break;
937        case GALLIUMOP_KCODEEND:
938            AsmGalliumPseudoOps::doKCodeEnd(*this, stmtPlace, linePtr);
939            break;
940        case GALLIUMOP_LOCALSIZE:
941            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
942                                    GALLIUMCVAL_LOCALSIZE);
943            break;
944        case GALLIUMOP_PRIORITY:
945            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
946                                    GALLIUMCVAL_PRIORITY);
947            break;
948        case GALLIUMOP_PRIVMODE:
949            AsmGalliumPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
950                                GALLIUMCVAL_PRIVMODE);
951            break;
952        case GALLIUMOP_PGMRSRC1:
953            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
954                                    GALLIUMCVAL_PGMRSRC1);
955            break;
956        case GALLIUMOP_PGMRSRC2:
957            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
958                                    GALLIUMCVAL_PGMRSRC2);
959            break;
960        case GALLIUMOP_PROGINFO:
961            AsmGalliumPseudoOps::doProgInfo(*this, stmtPlace, linePtr);
962            break;
963        case GALLIUMOP_SCRATCHBUFFER:
964            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
965                                    GALLIUMCVAL_SCRATCHBUFFER);
966            break;
967        case GALLIUMOP_SGPRSNUM:
968            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
969                                    GALLIUMCVAL_SGPRSNUM);
970            break;
971        case GALLIUMOP_TGSIZE:
972            AsmGalliumPseudoOps::setConfigBoolValue(*this, stmtPlace, linePtr,
973                                GALLIUMCVAL_TGSIZE);
974            break;
975        case GALLIUMOP_USERDATANUM:
976            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
977                                    GALLIUMCVAL_USERDATANUM);
978            break;
979        case GALLIUMOP_VGPRSNUM:
980            AsmGalliumPseudoOps::setConfigValue(*this, stmtPlace, linePtr,
981                                    GALLIUMCVAL_VGPRSNUM);
982            break;
983        default:
984            return false;
985    }
986    return true;
987}
988
989bool AsmGalliumHandler::prepareBinary()
990{   // before call we initialize pointers and datas
991    bool good = true;
992   
993    output.is64BitElf = assembler.is64Bit();
994    size_t sectionsNum = sections.size();
995    size_t kernelsNum = kernelStates.size();
996    output.deviceType = assembler.getDeviceType();
997    if (assembler.isaAssembler!=nullptr)
998    {   // make last kernel registers pool updates
999        if (kcodeSelStack.empty())
1000            saveKcodeCurrentAllocRegs();
1001        else
1002            while (!kcodeSelStack.empty())
1003            {   // pop from kcode stack and apply changes
1004                AsmGalliumPseudoOps::updateKCodeSel(*this, kcodeSelection);
1005                kcodeSelection = kcodeSelStack.top();
1006                kcodeSelStack.pop();
1007            }
1008    }
1009   
1010    for (size_t i = 0; i < sectionsNum; i++)
1011    {
1012        const AsmSection& asmSection = assembler.sections[i];
1013        const Section& section = sections[i];
1014        const size_t sectionSize = asmSection.getSize();
1015        const cxbyte* sectionData = (!asmSection.content.empty()) ?
1016                asmSection.content.data() : (const cxbyte*)"";
1017        switch(asmSection.type)
1018        {
1019            case AsmSectionType::CODE:
1020                output.codeSize = sectionSize;
1021                output.code = sectionData;
1022                break;
1023            case AsmSectionType::DATA:
1024                output.globalDataSize = sectionSize;
1025                output.globalData = sectionData;
1026                break;
1027            case AsmSectionType::EXTRA_PROGBITS:
1028            case AsmSectionType::EXTRA_NOTE:
1029            case AsmSectionType::EXTRA_NOBITS:
1030            case AsmSectionType::EXTRA_SECTION:
1031            {
1032                uint32_t elfSectType =
1033                       (asmSection.type==AsmSectionType::EXTRA_NOTE) ? SHT_NOTE :
1034                       (asmSection.type==AsmSectionType::EXTRA_NOBITS) ? SHT_NOBITS :
1035                             SHT_PROGBITS;
1036                uint32_t elfSectFlags = 
1037                    ((asmSection.flags&ASMELFSECT_ALLOCATABLE) ? SHF_ALLOC : 0) |
1038                    ((asmSection.flags&ASMELFSECT_WRITEABLE) ? SHF_WRITE : 0) |
1039                    ((asmSection.flags&ASMELFSECT_EXECUTABLE) ? SHF_EXECINSTR : 0);
1040                output.extraSections.push_back({section.name, sectionSize, sectionData,
1041                    asmSection.alignment!=0?asmSection.alignment:1, elfSectType,
1042                    elfSectFlags, ELFSECTID_NULL, 0, 0 });
1043                break;
1044            }
1045            case AsmSectionType::GALLIUM_COMMENT:
1046                output.commentSize = sectionSize;
1047                output.comment = (const char*)sectionData;
1048                break;
1049            default: // ignore other sections
1050                break;
1051        }
1052    }
1053   
1054    GPUArchitecture arch = getGPUArchitectureFromDeviceType(assembler.deviceType);
1055    // set up number of the allocated SGPRs and VGPRs for kernel
1056    cxuint maxSGPRsNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
1057   
1058    for (size_t i = 0; i < kernelsNum; i++)
1059    {
1060        if (!output.kernels[i].useConfig)
1061            continue;
1062        GalliumKernelConfig& config = output.kernels[i].config;
1063        cxuint userSGPRsNum = 4;
1064        /* include userData sgprs */
1065        cxuint dimMask = (config.dimMask!=BINGEN_DEFAULT) ? config.dimMask :
1066                ((config.pgmRSRC2>>7)&7);
1067        // extra sgprs for dimensions
1068        cxuint minRegsNum[2];
1069        getGPUSetupMinRegistersNum(arch, dimMask, userSGPRsNum,
1070                   ((config.tgSize) ? GPUSETUP_TGSIZE_EN : 0) |
1071                   ((config.scratchBufferSize!=0) ? GPUSETUP_SCRATCH_EN : 0), minRegsNum);
1072       
1073        if (config.usedSGPRsNum!=BINGEN_DEFAULT && maxSGPRsNum < config.usedSGPRsNum)
1074        {   // check only if sgprsnum set explicitly
1075            char numBuf[64];
1076            snprintf(numBuf, 64, "(max %u)", maxSGPRsNum);
1077            assembler.printError(assembler.kernels[i].sourcePos, (std::string(
1078                    "Number of total SGPRs for kernel '")+
1079                    output.kernels[i].kernelName.c_str()+"' is too high "+numBuf).c_str());
1080            good = false;
1081        }
1082       
1083        if (config.usedSGPRsNum==BINGEN_DEFAULT)
1084        {
1085            config.usedSGPRsNum = std::min(
1086                std::max(minRegsNum[0], kernelStates[i].allocRegs[0]) +
1087                    getGPUExtraRegsNum(arch, REGTYPE_SGPR, kernelStates[i].allocRegFlags),
1088                    maxSGPRsNum); // include all extra sgprs
1089        }
1090        if (config.usedVGPRsNum==BINGEN_DEFAULT)
1091            config.usedVGPRsNum = std::max(minRegsNum[1], kernelStates[i].allocRegs[1]);
1092    }
1093   
1094    // if set adds symbols to binary
1095    if (assembler.getFlags() & ASM_FORCE_ADD_SYMBOLS)
1096        for (const AsmSymbolEntry& symEntry: assembler.symbolMap)
1097        {
1098            if (!symEntry.second.hasValue)
1099                continue; // unresolved
1100            if (ELF32_ST_BIND(symEntry.second.info) == STB_LOCAL)
1101                continue; // local
1102            if (ELF32_ST_BIND(symEntry.second.info) == STB_GLOBAL)
1103            {
1104                assembler.printError(AsmSourcePos(), (std::string("Added symbol '")+
1105                    symEntry.first.c_str()+"' must not be a global").c_str());
1106                good = false;
1107                continue; // local
1108            }
1109            if (assembler.kernelMap.find(symEntry.first.c_str())!=assembler.kernelMap.end())
1110                continue; // if kernel name
1111            cxuint binSectId = (symEntry.second.sectionId != ASMSECT_ABS) ?
1112                    sections[symEntry.second.sectionId].elfBinSectId : ELFSECTID_ABS;
1113           
1114            output.extraSymbols.push_back({ symEntry.first, symEntry.second.value,
1115                    symEntry.second.size, binSectId, false, symEntry.second.info,
1116                    symEntry.second.other });
1117        }
1118   
1119    /// checking symbols and set offset for kernels
1120    const AsmSymbolMap& symbolMap = assembler.getSymbolMap();
1121    for (size_t ki = 0; ki < output.kernels.size(); ki++)
1122    {
1123        GalliumKernelInput& kinput = output.kernels[ki];
1124        auto it = symbolMap.find(kinput.kernelName);
1125        if (it == symbolMap.end() || !it->second.isDefined())
1126        {   // error, undefined
1127            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1128                        "Symbol for kernel '")+kinput.kernelName.c_str()+
1129                        "' is undefined").c_str());
1130            good = false;
1131            continue;
1132        }
1133        const AsmSymbol& symbol = it->second;
1134        if (!symbol.hasValue)
1135        {   // error, unresolved
1136            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1137                    "Symbol for kernel '") + kinput.kernelName.c_str() +
1138                    "' is not resolved").c_str());
1139            good = false;
1140            continue;
1141        }
1142        if (symbol.sectionId != codeSection)
1143        {   /// error, wrong section
1144            assembler.printError(assembler.kernels[ki].sourcePos, (std::string(
1145                    "Symbol for kernel '")+kinput.kernelName.c_str()+
1146                    "' is defined for section other than '.text'").c_str());
1147            good = false;
1148            continue;
1149        }
1150        kinput.offset = symbol.value;
1151    }
1152    return good;
1153}
1154
1155void AsmGalliumHandler::writeBinary(std::ostream& os) const
1156{
1157    GalliumBinGenerator binGenerator(&output);
1158    binGenerator.generate(os);
1159}
1160
1161void AsmGalliumHandler::writeBinary(Array<cxbyte>& array) const
1162{
1163    GalliumBinGenerator binGenerator(&output);
1164    binGenerator.generate(array);
1165}
Note: See TracBrowser for help on using the repository browser.