source: CLRX/CLRadeonExtender/trunk/amdbin/GalliumBinaries.cpp @ 3150

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

CLRadeonExtender: CLRX: small typos. GalliumBinary/GalliumDisasm?: Add support new LLVM 3.9.0 (spilledGPR info) and new Mesa3D 17.0.

File size: 28.0 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2017 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 <cassert>
22#include <climits>
23#include <algorithm>
24#include <cstdint>
25#include <utility>
26#include <memory>
27#include <CLRX/utils/Utilities.h>
28#include <CLRX/utils/MemAccess.h>
29#include <CLRX/utils/InputOutput.h>
30#include <CLRX/utils/Containers.h>
31#include <CLRX/amdbin/GalliumBinaries.h>
32
33using namespace CLRX;
34
35/* Gallium ELF binary */
36
37GalliumElfBinaryBase::GalliumElfBinaryBase() :
38        progInfosNum(0), progInfoEntries(nullptr), disasmSize(0), disasmOffset(0),
39        llvm390(false)
40{ }
41
42template<typename ElfBinary>
43void GalliumElfBinaryBase::loadFromElf(ElfBinary& elfBinary, size_t kernelsNum)
44{
45    uint16_t amdGpuConfigIndex = SHN_UNDEF;
46    try
47    { amdGpuConfigIndex = elfBinary.getSectionIndex(".AMDGPU.config"); }
48    catch(const Exception& ex)
49    { }
50   
51    uint16_t amdGpuDisasmIndex = SHN_UNDEF;
52    try
53    { amdGpuDisasmIndex = elfBinary.getSectionIndex(".AMDGPU.disasm"); }
54    catch(const Exception& ex)
55    { }
56    if (amdGpuDisasmIndex != SHN_UNDEF)
57    {   // set disassembler section
58        const auto& shdr = elfBinary.getSectionHeader(amdGpuDisasmIndex);
59        disasmOffset = ULEV(shdr.sh_offset);
60        disasmSize = ULEV(shdr.sh_size);
61    }
62   
63    uint16_t textIndex = SHN_UNDEF;
64    size_t textSize = 0;
65    try
66    {
67        textIndex = elfBinary.getSectionIndex(".text");
68        textSize = ULEV(elfBinary.getSectionHeader(textIndex).sh_size);
69    }
70    catch(const Exception& ex)
71    { }
72   
73    if (amdGpuConfigIndex == SHN_UNDEF || textIndex == SHN_UNDEF)
74        return;
75    // create amdGPU config systems
76    const auto& shdr = elfBinary.getSectionHeader(amdGpuConfigIndex);
77    size_t shdrSize = ULEV(shdr.sh_size);
78    size_t amdGPUConfigSize = (shdrSize / kernelsNum);
79    if (amdGPUConfigSize != 24 && amdGPUConfigSize != 40 &&
80        shdrSize % amdGPUConfigSize != 0)
81        throw Exception("Wrong size of .AMDGPU.config section!");
82    llvm390 = amdGPUConfigSize==40;
83   
84    const bool hasProgInfoMap = (elfBinary.getCreationFlags() &
85                        GALLIUM_ELF_CREATE_PROGINFOMAP) != 0;
86    /* check symbols */
87    const size_t symbolsNum = elfBinary.getSymbolsNum();
88    progInfosNum = 0;
89    if (hasProgInfoMap)
90        progInfoEntryMap.resize(symbolsNum);
91    for (size_t i = 0; i < symbolsNum; i++)
92    {
93        const auto& sym = elfBinary.getSymbol(i);
94        const char* symName = elfBinary.getSymbolName(i);
95        if (ULEV(sym.st_shndx) == textIndex && ELF32_ST_BIND(sym.st_info) == STB_GLOBAL)
96        {
97            if (ULEV(sym.st_value) >= textSize)
98                throw Exception("kernel symbol offset out of range");
99            if (hasProgInfoMap)
100                progInfoEntryMap[progInfosNum] = std::make_pair(symName, 3*progInfosNum);
101            progInfosNum++;
102        }
103    }
104    if (progInfosNum*amdGPUConfigSize != ULEV(shdr.sh_size))
105        throw Exception("Number of symbol kernels doesn't match progInfos number!");
106    cxbyte* binaryCode = (cxbyte*)elfBinary.getBinaryCode();
107    progInfoEntries = reinterpret_cast<GalliumProgInfoEntry*>(binaryCode +
108                ULEV(shdr.sh_offset));
109   
110    if (hasProgInfoMap)
111    {
112        progInfoEntryMap.resize(progInfosNum);
113        mapSort(progInfoEntryMap.begin(), progInfoEntryMap.end(), CStringLess());
114    }
115}
116
117GalliumElfBinaryBase::~GalliumElfBinaryBase()
118{ }
119
120GalliumElfBinary32::GalliumElfBinary32()
121{ }
122
123GalliumElfBinary32::~GalliumElfBinary32()
124{ }
125
126GalliumElfBinary32::GalliumElfBinary32(size_t binaryCodeSize, cxbyte* binaryCode,
127           Flags creationFlags, size_t kernelsNum) :
128           ElfBinary32(binaryCodeSize, binaryCode, creationFlags)
129       
130{
131    loadFromElf(static_cast<const ElfBinary32&>(*this), kernelsNum);
132}
133
134GalliumElfBinary64::GalliumElfBinary64()
135{ }
136
137GalliumElfBinary64::~GalliumElfBinary64()
138{ }
139
140GalliumElfBinary64::GalliumElfBinary64(size_t binaryCodeSize, cxbyte* binaryCode,
141           Flags creationFlags, size_t kernelsNum) :
142           ElfBinary64(binaryCodeSize, binaryCode, creationFlags)
143       
144{
145    loadFromElf(static_cast<const ElfBinary64&>(*this), kernelsNum);
146}
147
148uint32_t GalliumElfBinaryBase::getProgramInfoEntriesNum(uint32_t index) const
149{ return 3; }
150
151uint32_t GalliumElfBinaryBase::getProgramInfoEntryIndex(const char* name) const
152{
153    ProgInfoEntryIndexMap::const_iterator it = binaryMapFind(progInfoEntryMap.begin(),
154                         progInfoEntryMap.end(), name, CStringLess());
155    if (it == progInfoEntryMap.end())
156        throw Exception("Can't find GalliumElf ProgInfoEntry");
157    return it->second;
158}
159
160const GalliumProgInfoEntry* GalliumElfBinaryBase::getProgramInfo(uint32_t index) const
161{
162    return progInfoEntries + index*3U;
163}
164
165GalliumProgInfoEntry* GalliumElfBinaryBase::getProgramInfo(uint32_t index)
166{
167    return progInfoEntries + index*3U;
168}
169
170/* main GalliumBinary */
171
172template<typename GalliumElfBinary>
173static void verifyKernelSymbols(size_t kernelsNum, const GalliumKernel* kernels,
174                const GalliumElfBinary& elfBinary)
175{
176    size_t symIndex = 0;
177    const size_t symsNum = elfBinary.getSymbolsNum();
178    uint16_t textIndex = elfBinary.getSectionIndex(".text");
179    for (uint32_t i = 0; i < kernelsNum; i++)
180    {
181        const GalliumKernel& kernel = kernels[i];
182        for (; symIndex < symsNum; symIndex++)
183        {
184            const auto& sym = elfBinary.getSymbol(symIndex);
185            const char* symName = elfBinary.getSymbolName(symIndex);
186            // kernel symol must be defined as global and must be bound to text section
187            if (ULEV(sym.st_shndx) == textIndex &&
188                ELF32_ST_BIND(sym.st_info) == STB_GLOBAL)
189            {   // names must be stored in order
190                if (kernel.kernelName != symName)
191                    throw Exception("Kernel symbols out of order!");
192                if (ULEV(sym.st_value) != kernel.offset)
193                    throw Exception("Kernel symbol value and Kernel "
194                                "offset doesn't match");
195                break;
196            }
197        }
198        if (symIndex >= symsNum)
199            throw Exception("Number of kernels in ElfBinary and "
200                        "MainBinary doesn't match");
201        symIndex++;
202    }
203}
204
205GalliumBinary::GalliumBinary(size_t _binaryCodeSize, cxbyte* _binaryCode,
206                 Flags _creationFlags) : creationFlags(_creationFlags),
207         binaryCodeSize(_binaryCodeSize), binaryCode(_binaryCode),
208         kernelsNum(0), sectionsNum(0), kernels(nullptr), sections(nullptr),
209         elf64BitBinary(false), mesa170(false)
210{
211    if (binaryCodeSize < 4)
212        throw Exception("GalliumBinary is too small!!!");
213    uint32_t* data32 = reinterpret_cast<uint32_t*>(binaryCode);
214    kernelsNum = ULEV(*data32);
215    if (binaryCodeSize < uint64_t(kernelsNum)*16U)
216        throw Exception("Kernels number is too big!");
217    kernels.reset(new GalliumKernel[kernelsNum]);
218    cxbyte* data = binaryCode + 4;
219    // parse kernels symbol info and their arguments
220    for (cxuint i = 0; i < kernelsNum; i++)
221    {
222        GalliumKernel& kernel = kernels[i];
223        if (usumGt(uint32_t(data-binaryCode), 4U, binaryCodeSize))
224            throw Exception("GalliumBinary is too small!!!");
225       
226        const cxuint symNameLen = ULEV(*reinterpret_cast<const uint32_t*>(data));
227        data+=4;
228        if (usumGt(uint32_t(data-binaryCode), symNameLen, binaryCodeSize))
229            throw Exception("Kernel name length is too long!");
230       
231        kernel.kernelName.assign((const char*)data, symNameLen);
232       
233        /// check kernel name order (sorted order is required by Mesa3D radeon driver)
234        if (i != 0 && kernel.kernelName < kernels[i-1].kernelName)
235            throw Exception("Unsorted kernel table!");
236       
237        data += symNameLen;
238        if (usumGt(uint32_t(data-binaryCode), 12U, binaryCodeSize))
239            throw Exception("GalliumBinary is too small!!!");
240       
241        data32 = reinterpret_cast<uint32_t*>(data);
242        kernel.sectionId = ULEV(data32[0]);
243        kernel.offset = ULEV(data32[1]);
244        const uint32_t argsNum = ULEV(data32[2]);
245        data32 += 3;
246        data = reinterpret_cast<cxbyte*>(data32);
247       
248        if (UINT32_MAX/24U < argsNum)
249            throw Exception("Number of arguments number is too high!");
250        if (usumGt(uint32_t(data-binaryCode), 24U*argsNum, binaryCodeSize))
251            throw Exception("GalliumBinary is too small!!!");
252       
253        kernel.argInfos.resize(argsNum);
254        for (uint32_t j = 0; j < argsNum; j++)
255        {
256            GalliumArgInfo& argInfo = kernel.argInfos[j];
257            const cxuint type = ULEV(data32[0]);
258            // accept not known arg type by this CLRadeonExtender
259            if (type > 255)
260                throw Exception("Type of kernel argument out of handled range");
261            argInfo.type = GalliumArgType(type);
262            argInfo.size = ULEV(data32[1]);
263            argInfo.targetSize = ULEV(data32[2]);
264            argInfo.targetAlign = ULEV(data32[3]);
265            argInfo.signExtended = ULEV(data32[4])!=0;
266            const cxuint semType = ULEV(data32[5]);
267            // accept not known semantic type by this CLRadeonExtender
268            if (semType > 255)
269                throw Exception("Semantic of kernel argument out of handled range");
270            argInfo.semantic = GalliumArgSemantic(semType);
271            data32 += 6;
272        }
273        data = reinterpret_cast<cxbyte*>(data32);
274    }
275   
276    if (usumGt(uint32_t(data-binaryCode), 4U, binaryCodeSize))
277        throw Exception("GalliumBinary is too small!!!");
278   
279    sectionsNum = ULEV(data32[0]);
280    if (binaryCodeSize-(data-binaryCode) < uint64_t(sectionsNum)*20U)
281        throw Exception("Sections number is too big!");
282    sections.reset(new GalliumSection[sectionsNum]);
283    // parse sections and their content
284    data32++;
285    data += 4;
286   
287    uint32_t elfSectionId = 0; // initialize warning
288    for (uint32_t i = 0; i < sectionsNum; i++)
289    {
290        GalliumSection& section = sections[i];
291        if (usumGt(uint32_t(data-binaryCode), 20U, binaryCodeSize))
292            throw Exception("GalliumBinary is too small!!!");
293       
294        section.sectionId = ULEV(data32[0]);
295        const uint32_t secType = ULEV(data32[1]);
296        if (secType > 255)
297            throw Exception("Type of section out of range");
298        section.type = GalliumSectionType(secType);
299        section.size = ULEV(data32[2]);
300        const uint32_t sizeOfData = ULEV(data32[3]);
301        const uint32_t sizeFromHeader = ULEV(data32[4]); // from LLVM binary
302        if (section.size != sizeOfData-4 || section.size != sizeFromHeader)
303            throw Exception("Section size fields doesn't match itself!");
304       
305        data = reinterpret_cast<cxbyte*>(data32+5);
306        if (usumGt(uint32_t(data-binaryCode), section.size, binaryCodeSize))
307            throw Exception("Section size is too big!!!");
308       
309        section.offset = data-binaryCode;
310       
311        if (!elfBinary && (section.type == GalliumSectionType::TEXT ||
312            section.type == GalliumSectionType::TEXT_EXECUTABLE_170))
313        {   // if new Mesa3D 17.0
314            mesa170 = (section.type == GalliumSectionType::TEXT_EXECUTABLE_170);
315            if (section.size < sizeof(Elf32_Ehdr))
316                throw Exception("Wrong GalliumElfBinary size");
317            const Elf32_Ehdr& ehdr = *reinterpret_cast<const Elf32_Ehdr*>(data);
318            if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
319            {   // 32-bit
320                elfBinary.reset(new GalliumElfBinary32(section.size, data,
321                                 creationFlags>>GALLIUM_INNER_SHIFT, kernelsNum));
322                elf64BitBinary = false;
323            }
324            else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
325            {   // 64-bit
326                elfSectionId = section.sectionId;
327                elfBinary.reset(new GalliumElfBinary64(section.size, data,
328                                 creationFlags>>GALLIUM_INNER_SHIFT, kernelsNum));
329                elf64BitBinary = true;
330            }
331            else // wrong class
332                throw Exception("Wrong GalliumElfBinary class");
333        }
334        data += section.size;
335        data32 = reinterpret_cast<uint32_t*>(data);
336    }
337   
338    if (!elfBinary)
339        throw Exception("Gallium Elf binary not found!");
340    for (uint32_t i = 0; i < kernelsNum; i++)
341        if (kernels[i].sectionId != elfSectionId)
342            throw Exception("Kernel not in text section!");
343    // verify kernel offsets
344    if (!elf64BitBinary)
345        verifyKernelSymbols(kernelsNum, kernels.get(), getElfBinary32());
346    else
347        verifyKernelSymbols(kernelsNum, kernels.get(), getElfBinary64());
348}
349
350uint32_t GalliumBinary::getKernelIndex(const char* name) const
351{
352    const GalliumKernel v = { name };
353    const GalliumKernel* it = binaryFind(kernels.get(), kernels.get()+kernelsNum, v,
354       [](const GalliumKernel& k1, const GalliumKernel& k2)
355       { return k1.kernelName < k2.kernelName; });
356    if (it == kernels.get()+kernelsNum || it->kernelName != name)
357        throw Exception("Can't find Gallium Kernel Index");
358    return it-kernels.get();
359}
360
361void GalliumInput::addEmptyKernel(const char* kernelName)
362{
363    GalliumKernelInput kinput = { kernelName, {
364        /* default values */
365        { 0x0000b848U, 0x000c0000U },
366        { 0x0000b84cU, 0x00001788U },
367        { 0x0000b860U, 0 } }, false, { }, 0, {} };
368    kinput.config.dimMask = BINGEN_DEFAULT;
369    kinput.config.usedVGPRsNum = BINGEN_DEFAULT;
370    kinput.config.usedSGPRsNum = BINGEN_DEFAULT;
371    kinput.config.floatMode = 0xc0;
372    kinput.config.userDataNum = 4;
373    kinput.config.spilledVGPRs = kinput.config.spilledSGPRs = 0;
374    kernels.push_back(std::move(kinput));
375}
376
377/*
378 * GalliumBinGenerator
379 */
380
381GalliumBinGenerator::GalliumBinGenerator() : manageable(false), input(nullptr)
382{ }
383
384GalliumBinGenerator::GalliumBinGenerator(const GalliumInput* galliumInput)
385        : manageable(false), input(galliumInput)
386{ }
387
388GalliumBinGenerator::GalliumBinGenerator(bool _64bitMode, GPUDeviceType deviceType,
389        size_t codeSize, const cxbyte* code,
390        size_t globalDataSize, const cxbyte* globalData,
391        const std::vector<GalliumKernelInput>& kernels)
392        : manageable(true), input(nullptr)
393{
394    input = new GalliumInput{ _64bitMode, deviceType, globalDataSize, globalData, kernels,
395            codeSize, code, 0, nullptr };
396}
397
398GalliumBinGenerator::GalliumBinGenerator(bool _64bitMode, GPUDeviceType deviceType,
399        size_t codeSize, const cxbyte* code,
400        size_t globalDataSize, const cxbyte* globalData,
401        std::vector<GalliumKernelInput>&& kernels)
402        : manageable(true), input(nullptr)
403{
404    input = new GalliumInput{ _64bitMode, deviceType, globalDataSize, globalData,
405        std::move(kernels), codeSize, code, 0, nullptr };
406}
407
408
409GalliumBinGenerator::~GalliumBinGenerator()
410{
411    if (manageable)
412        delete input;
413}
414
415void GalliumBinGenerator::setInput(const GalliumInput* input)
416{
417    if (manageable)
418        delete input;
419    manageable = false;
420    this->input = input;
421}
422
423// section index for symbol binding
424static const uint16_t mainBuiltinSectionTable[] =
425{
426    8, // ELFSECTID_SHSTRTAB
427    10, // ELFSECTID_STRTAB
428    9, // ELFSECTID_SYMTAB
429    SHN_UNDEF, // ELFSECTID_DYNSTR
430    SHN_UNDEF, // ELFSECTID_DYNSYM
431    1, // ELFSECTID_TEXT
432    5, // ELFSECTID_RODATA
433    2, // ELFSECTID_DATA
434    3, // ELFSECTID_BSS
435    6, // ELFSECTID_COMMENT
436    4, // GALLIUMSECTID_GPUCONFIG
437    7  // GALLIUMSECTID_NOTEGNUSTACK
438};
439
440// section index for symbol binding
441static const uint16_t mainBuiltinSectionTable2[] =
442{
443    7, // ELFSECTID_SHSTRTAB
444    9, // ELFSECTID_STRTAB
445    8, // ELFSECTID_SYMTAB
446    SHN_UNDEF, // ELFSECTID_DYNSTR
447    SHN_UNDEF, // ELFSECTID_DYNSYM
448    1, // ELFSECTID_TEXT
449    SHN_UNDEF, // ELFSECTID_RODATA
450    2, // ELFSECTID_DATA
451    3, // ELFSECTID_BSS
452    5, // ELFSECTID_COMMENT
453    4, // GALLIUMSECTID_GPUCONFIG
454    6  // GALLIUMSECTID_NOTEGNUSTACK
455};
456
457class CLRX_INTERNAL AmdGpuConfigContent: public ElfRegionContent
458{
459private:
460    const Array<uint32_t>& kernelsOrder;
461    const GalliumInput& input;
462public:
463    AmdGpuConfigContent(const Array<uint32_t>& inKernelsOrder,
464            const GalliumInput& inInput) : kernelsOrder(inKernelsOrder), input(inInput)
465    { }
466   
467    void operator()(FastOutputBuffer& fob) const
468    {
469        const GPUArchitecture arch = getGPUArchitectureFromDeviceType(input.deviceType);
470        const cxuint ldsShift = arch<GPUArchitecture::GCN1_1 ? 8 : 9;
471        const uint32_t ldsMask = (1U<<ldsShift)-1U;
472        for (uint32_t korder: kernelsOrder)
473        {
474            const GalliumKernelInput& kernel = input.kernels[korder];
475            GalliumProgInfoEntry outEntries[3];
476            if (kernel.useConfig)
477            {
478                const GalliumKernelConfig& config = kernel.config;
479                outEntries[0].address = ULEV(0x0000b848U);
480                outEntries[1].address = ULEV(0x0000b84cU);
481                outEntries[2].address = ULEV(0x0000b860U);
482               
483                uint32_t scratchBlocks = ((config.scratchBufferSize<<6) + 1023)>>10;
484                uint32_t dimValues = 0;
485                if (config.dimMask != BINGEN_DEFAULT)
486                    dimValues = ((config.dimMask&7)<<7) |
487                            (((config.dimMask&4) ? 2 : (config.dimMask&2) ? 1 : 0)<<11);
488                else
489                    dimValues |= (config.pgmRSRC2 & 0x1b80U);
490                cxuint sgprsNum = std::max(config.usedSGPRsNum, 1U);
491                cxuint vgprsNum = std::max(config.usedVGPRsNum, 1U);
492                /// pgmRSRC1
493                outEntries[0].value = (config.pgmRSRC1) | ((vgprsNum-1)>>2) |
494                        (((sgprsNum-1)>>3)<<6) | ((uint32_t(config.floatMode)&0xff)<<12) |
495                        (config.ieeeMode?1U<<23:0) | (uint32_t(config.priority&3)<<10) |
496                        (config.privilegedMode?1U<<20:0) | (config.dx10Clamp?1U<<21:0) |
497                        (config.debugMode?1U<<22:0);
498               
499                outEntries[1].value = (config.pgmRSRC2 & 0xffffe440U) |
500                        (config.userDataNum<<1) | ((config.tgSize) ? 0x400 : 0) |
501                        ((config.scratchBufferSize)?1:0) | dimValues |
502                        (((config.localSize+ldsMask)>>ldsShift)<<15) |
503                        ((uint32_t(config.exceptions)&0x7f)<<24);
504                outEntries[2].value = (scratchBlocks)<<12;
505                for (cxuint k = 0; k < 3; k++)
506                    outEntries[k].value = ULEV(outEntries[k].value);
507            }
508            else
509                for (cxuint k = 0; k < 3; k++)
510                {
511                    outEntries[k].address = ULEV(kernel.progInfo[k].address);
512                    outEntries[k].value = ULEV(kernel.progInfo[k].value);
513                }
514            fob.writeArray(3, outEntries);
515        }
516    }
517};
518
519template<typename Types>
520static void putSectionsAndSymbols(ElfBinaryGenTemplate<Types>& elfBinGen,
521      const GalliumInput* input, const Array<uint32_t>& kernelsOrder,
522      const AmdGpuConfigContent& amdGpuConfigContent)
523{
524    const char* comment = "CLRX GalliumBinGenerator " CLRX_VERSION;
525    uint32_t commentSize = ::strlen(comment);
526   
527    typedef ElfRegionTemplate<Types> ElfRegion;
528    typedef ElfSymbolTemplate<Types> ElfSymbol;
529    const uint32_t kernelsNum = input->kernels.size();
530    elfBinGen.addRegion(ElfRegion(input->codeSize, input->code, 256, ".text",
531            SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR));
532    elfBinGen.addRegion(ElfRegion(0, (const cxbyte*)nullptr, 4, ".data",
533            SHT_PROGBITS, SHF_ALLOC|SHF_WRITE));
534    elfBinGen.addRegion(ElfRegion(0, (const cxbyte*)nullptr, 4, ".bss",
535            SHT_NOBITS, SHF_ALLOC|SHF_WRITE));
536    // write configuration for kernel execution
537    elfBinGen.addRegion(ElfRegion(uint64_t(24U)*kernelsNum, &amdGpuConfigContent, 1,
538            ".AMDGPU.config", SHT_PROGBITS, 0));
539   
540    if (input->globalData!=nullptr)
541        elfBinGen.addRegion(ElfRegion(input->globalDataSize, input->globalData, 4,
542                ".rodata", SHT_PROGBITS, SHF_ALLOC));
543   
544    if (input->comment!=nullptr)
545    {   // if comment, store comment section
546        comment = input->comment;
547        commentSize = input->commentSize;
548        if (commentSize==0)
549            commentSize = ::strlen(comment);
550    }
551    elfBinGen.addRegion(ElfRegion(commentSize, (const cxbyte*)comment, 1,
552                ".comment", SHT_PROGBITS, SHF_STRINGS|SHF_MERGE, 0, 0, 0, 1));
553    elfBinGen.addRegion(ElfRegion(0, (const cxbyte*)nullptr, 1, ".note.GNU-stack",
554            SHT_PROGBITS, 0));
555    elfBinGen.addRegion(ElfRegion::shstrtabSection());
556    elfBinGen.addRegion(ElfRegion::sectionHeaderTable());
557    elfBinGen.addRegion(ElfRegion::symtabSection());
558    elfBinGen.addRegion(ElfRegion::strtabSection());
559    /* symbols */
560    /// EndOfTextLabel - ?? always is at end of symbol table
561    elfBinGen.addSymbol({"EndOfTextLabel", 1, ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE),
562            0, false, uint32_t(input->codeSize), 0});
563    const cxuint sectSymsNum = 6 + (input->globalData!=nullptr);
564    // local symbols for sections
565    for (cxuint i = 0; i < sectSymsNum; i++)
566        elfBinGen.addSymbol({"", uint16_t(i+1), ELF32_ST_INFO(STB_LOCAL, STT_SECTION),
567                0, false, 0, 0});
568    for (uint32_t korder: kernelsOrder)
569    {
570        const GalliumKernelInput& kernel = input->kernels[korder];
571        elfBinGen.addSymbol({kernel.kernelName.c_str(), 1,
572                ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, false, kernel.offset, 0});
573    }
574   
575    /* choose builtin section table and extraSectionStartIndex */
576    const uint16_t* curMainBuiltinSections = (input->globalData!=nullptr) ?
577            mainBuiltinSectionTable : mainBuiltinSectionTable2;
578    cxuint startSectionIndex = (input->globalData!=nullptr) ? 11 : 10;
579   
580    /* extra sections */
581    for (const BinSection& section: input->extraSections)
582        elfBinGen.addRegion(ElfRegion(section, curMainBuiltinSections,
583                         GALLIUMSECTID_MAX, startSectionIndex));
584    /* extra symbols */
585    for (const BinSymbol& symbol: input->extraSymbols)
586        elfBinGen.addSymbol(ElfSymbol(symbol, curMainBuiltinSections,
587                         GALLIUMSECTID_MAX, startSectionIndex));
588}
589
590void GalliumBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
591             Array<cxbyte>* aPtr) const
592{
593    const uint32_t kernelsNum = input->kernels.size();
594    /* compute size of binary */
595    uint64_t elfSize = 0;
596    uint64_t binarySize = uint64_t(8) + size_t(kernelsNum)*16U + 20U /* section */;
597    for (const GalliumKernelInput& kernel: input->kernels)
598        binarySize += uint64_t(kernel.argInfos.size())*24U + kernel.kernelName.size();
599   
600    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
601    const cxuint maxSGPRSNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, 0);
602    const cxuint maxVGPRSNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
603    for (const GalliumKernelInput& kernel: input->kernels)
604        if (kernel.useConfig)
605        {
606            const GalliumKernelConfig& config = kernel.config;
607            if (config.usedVGPRsNum > maxVGPRSNum)
608                throw Exception("Used VGPRs number out of range");
609            if (config.usedSGPRsNum > maxSGPRSNum)
610                throw Exception("Used SGPRs number out of range");
611            if (config.localSize > 32768)
612                throw Exception("LocalSize out of range");
613            if (config.priority >= 4)
614                throw Exception("Priority out of range");
615            if (config.userDataNum > 16)
616                throw Exception("UserDataNum out of range");
617        }
618   
619    // sort kernels by name (for correct order in binary file) */
620    Array<uint32_t> kernelsOrder(kernelsNum);
621    for (cxuint i = 0; i < kernelsNum; i++)
622        kernelsOrder[i] = i;
623    std::sort(kernelsOrder.begin(), kernelsOrder.end(),
624          [this](const uint32_t& a,const uint32_t& b)
625          { return input->kernels[a].kernelName < input->kernels[b].kernelName; });
626   
627    std::unique_ptr<ElfBinaryGen32> elfBinGen32;
628    std::unique_ptr<ElfBinaryGen64> elfBinGen64;
629   
630    AmdGpuConfigContent amdGpuConfigContent(kernelsOrder, *input);
631    if (!input->is64BitElf)
632    {   /* 32-bit ELF */
633        elfBinGen32.reset(new ElfBinaryGen32({ 0, 0, ELFOSABI_SYSV, 0,  ET_REL, 0,
634                    EV_CURRENT, UINT_MAX, 0, 0 }));
635        putSectionsAndSymbols(*elfBinGen32, input, kernelsOrder, amdGpuConfigContent);
636        elfSize = elfBinGen32->countSize();
637    }
638    else
639    {   /* 64-bit ELF */
640        elfBinGen64.reset(new ElfBinaryGen64({ 0, 0, ELFOSABI_SYSV, 0,  ET_REL, 0,
641                    EV_CURRENT, UINT_MAX, 0, 0 }));
642        putSectionsAndSymbols(*elfBinGen64, input, kernelsOrder, amdGpuConfigContent);
643        elfSize = elfBinGen64->countSize();
644    }
645
646    binarySize += elfSize;
647   
648    if (
649#ifdef HAVE_64BIT
650        !input->is64BitElf &&
651#endif
652        elfSize > UINT32_MAX)
653        throw Exception("Elf binary size is too big!");
654   
655#ifdef HAVE_32BIT
656    if (binarySize > UINT32_MAX)
657        throw Exception("Binary size is too big!");
658#endif
659    /****
660     * prepare for write binary to output
661     ****/
662    std::unique_ptr<std::ostream> outStreamHolder;
663    std::ostream* os = nullptr;
664    if (aPtr != nullptr)
665    {
666        aPtr->resize(binarySize);
667        outStreamHolder.reset(
668                new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
669        os = outStreamHolder.get();
670    }
671    else if (vPtr != nullptr)
672    {
673        vPtr->resize(binarySize);
674        outStreamHolder.reset(new VectorOStream(*vPtr));
675        os = outStreamHolder.get();
676    }
677    else // from argument
678        os = osPtr;
679   
680    const std::ios::iostate oldExceptions = os->exceptions();
681    try
682    {
683    os->exceptions(std::ios::failbit | std::ios::badbit);
684    /****
685     * write binary to output
686     ****/
687    FastOutputBuffer bos(256, *os);
688    bos.writeObject<uint32_t>(LEV(kernelsNum));
689    for (uint32_t korder: kernelsOrder)
690    {
691        const GalliumKernelInput& kernel = input->kernels[korder];
692        if (kernel.offset >= input->codeSize)
693            throw Exception("Kernel offset out of range");
694       
695        bos.writeObject<uint32_t>(LEV(uint32_t(kernel.kernelName.size())));
696        bos.writeArray(kernel.kernelName.size(), kernel.kernelName.c_str());
697        const uint32_t other[3] = { 0, LEV(kernel.offset),
698            LEV(cxuint(kernel.argInfos.size())) };
699        bos.writeArray(3, other);
700       
701        for (const GalliumArgInfo arg: kernel.argInfos)
702        {
703            const uint32_t argData[6] = { LEV(cxuint(arg.type)),
704                LEV(arg.size), LEV(arg.targetSize), LEV(arg.targetAlign),
705                LEV(arg.signExtended?1U:0U), LEV(cxuint(arg.semantic)) };
706            bos.writeArray(6, argData);
707        }
708    }
709    /* section */
710    {
711        const uint32_t section[6] = { LEV(1U), LEV(0U), LEV(0U), LEV(uint32_t(elfSize)),
712            LEV(uint32_t(elfSize+4)), LEV(uint32_t(elfSize)) };
713        bos.writeArray(6, section);
714    }
715    if (!input->is64BitElf)
716        elfBinGen32->generate(bos);
717    else // 64-bit
718        elfBinGen64->generate(bos);
719    assert(bos.getWritten() == binarySize);
720    }
721    catch(...)
722    {
723        os->exceptions(oldExceptions);
724        throw;
725    }
726    os->exceptions(oldExceptions);
727}
728
729void GalliumBinGenerator::generate(Array<cxbyte>& array) const
730{
731    generateInternal(nullptr, nullptr, &array);
732}
733
734void GalliumBinGenerator::generate(std::ostream& os) const
735{
736    generateInternal(&os, nullptr, nullptr);
737}
738
739void GalliumBinGenerator::generate(std::vector<char>& v) const
740{
741    generateInternal(nullptr, &v, nullptr);
742}
Note: See TracBrowser for help on using the repository browser.