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

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

CLRadeonExtender: Update copyright's years.

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