source: CLRX/CLRadeonExtender/trunk/amdbin/AmdBinGen.cpp @ 3306

Last change on this file since 3306 was 3306, checked in by matszpk, 11 months ago

CLRadeonExtender: Added support for GFX901 (next RX VEGA with HBCC) device.

File size: 72.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 <cstdio>
23#include <cstring>
24#include <cstdint>
25#include <fstream>
26#include <algorithm>
27#include <bitset>
28#include <string>
29#include <vector>
30#include <memory>
31#include <mutex>
32#include <CLRX/utils/Containers.h>
33#include <CLRX/utils/Utilities.h>
34#include <CLRX/utils/MemAccess.h>
35#include <CLRX/utils/InputOutput.h>
36#include <CLRX/amdbin/AmdBinGen.h>
37
38using namespace CLRX;
39
40static inline void putCALNoteLE(FastOutputBuffer& bos, uint32_t type, uint32_t descSize)
41{
42    const CALNoteHeader nhdr = { LEV(8U), LEV(descSize), LEV(type),
43        { 'A', 'T', 'I', ' ', 'C', 'A', 'L', 0 } };
44    bos.writeObject(nhdr);
45}
46
47static inline void putCALUavEntryLE(FastOutputBuffer& bos, uint32_t uavId, uint32_t f1,
48          uint32_t f2, uint32_t type)
49{
50    const CALUAVEntry uavEntry = { LEV(uavId), LEV(f1), LEV(f2), LEV(type) };
51    bos.writeObject(uavEntry);
52}
53
54static inline void putCBMaskLE(FastOutputBuffer& bos,
55         uint32_t index, uint32_t size)
56{
57    const CALConstantBufferMask cbMask = { LEV(index), LEV(size) };
58    bos.writeObject(cbMask);
59}
60
61static inline void putSamplerEntryLE(FastOutputBuffer& bos,
62         uint32_t input, uint32_t sampler)
63{
64    const CALSamplerMapEntry samplerEntry = { LEV(input), LEV(sampler) };
65    bos.writeObject(samplerEntry);
66}
67
68static inline void putProgInfoEntryLE(FastOutputBuffer& bos,
69          uint32_t address, uint32_t value)
70{
71    const CALProgramInfoEntry piEntry = { LEV(address), LEV(value) };
72    bos.writeObject(piEntry);
73}
74
75// e_type (16-bit)
76static const uint16_t gpuDeviceCodeTable[24] =
77{
78    0x3ff, // GPUDeviceType::CAPE_VERDE
79    0x3fe, // GPUDeviceType::PITCAIRN
80    0x3fd, // GPUDeviceType::TAHITI
81    0x402, // GPUDeviceType::OLAND
82    0x403, // GPUDeviceType::BONAIRE
83    0x404, // GPUDeviceType::SPECTRE
84    0x405, // GPUDeviceType::SPOOKY
85    0x406, // GPUDeviceType::KALINDI
86    0x407, // GPUDeviceType::HAINAN
87    0x408, // GPUDeviceType::HAWAII
88    0x409, // GPUDeviceType::ICELAND
89    0x40a, // GPUDeviceType::TONGA
90    0x40b, // GPUDeviceType::MULLINS
91    0x40c, // GPUDeviceType::FIJI
92    0x40d, // GPUDeviceType::CARRIZO
93    0x411, // GPUDeviceType::DUMMY
94    0x40f, // GPUDeviceType::GOOSE
95    0x40e, // GPUDeviceType::HORSE
96    0x411, // GPUDeviceType::STONEY
97    0x40e, // GPUDeviceType::ELLESMERE
98    0x40f, // GPUDeviceType::BAFFIN
99    0x412, // GPUDeviceType::GFX804
100    0xffff, // GPUDeviceType::GFX900
101    0xffff  // GPUDeviceType::GFX901
102};
103
104/// CALNoteEntry (32-bit)
105static const uint32_t gpuDeviceInnerCodeTable[24] =
106{
107    0x1c, // GPUDeviceType::CAPE_VERDE
108    0x1b, // GPUDeviceType::PITCAIRN
109    0x1a, // GPUDeviceType::TAHITI
110    0x20, // GPUDeviceType::OLAND
111    0x21, // GPUDeviceType::BONAIRE
112    0x22, // GPUDeviceType::SPECTRE
113    0x23, // GPUDeviceType::SPOOKY
114    0x24, // GPUDeviceType::KALINDI
115    0x25, // GPUDeviceType::HAINAN
116    0x27, // GPUDeviceType::HAWAII
117    0x29, // GPUDeviceType::ICELAND
118    0x2a, // GPUDeviceType::TONGA
119    0x2b, // GPUDeviceType::MULLINS
120    0x2d, // GPUDeviceType::FIJI
121    0x2e, // GPUDeviceType::CARRIZO
122    0x31, // GPUDeviceType::DUMMY
123    0x2c, // GPUDeviceType::GOOSE
124    0x2f, // GPUDeviceType::HORSE
125    0x31, // GPUDeviceType::STONEY
126    0x2f, // GPUDeviceType::ELLESMERE
127    0x2c, // GPUDeviceType::BAFFIN
128    0x32, // GPUDeviceType::GFX804
129    UINT_MAX, // GPUDeviceType::GFX900
130    UINT_MAX  // GPUDeviceType::GFX901
131};
132
133void AmdInput::addKernel(const AmdKernelInput& kernelInput)
134{
135    kernels.push_back(kernelInput);
136}
137
138void AmdInput::addKernel(AmdKernelInput&& kernelInput)
139{
140    kernels.push_back(kernelInput);
141}
142
143void AmdInput::addKernel(const char* kernelName, size_t codeSize,
144       const cxbyte* code, const AmdKernelConfig& config,
145       size_t dataSize, const cxbyte* data)
146{
147    kernels.push_back({ kernelName, dataSize, data, 0, nullptr, 0, nullptr, {},
148                true, config, codeSize, code });
149}
150
151void AmdInput::addKernel(const char* kernelName, size_t codeSize,
152       const cxbyte* code, const std::vector<CALNoteInput>& calNotes, const cxbyte* header,
153       size_t metadataSize, const char* metadata, size_t dataSize, const cxbyte* data)
154{
155    kernels.push_back({ kernelName, dataSize, data, 32, header,
156        metadataSize, metadata, calNotes, false, AmdKernelConfig(), codeSize, code });
157}
158
159void AmdInput::addEmptyKernel(const char* kernelName)
160{
161    AmdKernelInput kernel{};
162    kernel.kernelName = kernelName;
163    kernel.config.floatMode = 0xc0;
164    kernel.config.dimMask = BINGEN_DEFAULT;
165    kernel.config.usedSGPRsNum = kernel.config.usedVGPRsNum = BINGEN_DEFAULT;
166    kernel.config.hwRegion = BINGEN_DEFAULT;
167    kernel.config.uavId = kernel.config.privateId = kernel.config.printfId =
168        kernel.config.uavPrivate = kernel.config.constBufferId = BINGEN_DEFAULT;
169    kernels.push_back(std::move(kernel));
170}
171
172AmdGPUBinGenerator::AmdGPUBinGenerator() : manageable(false), input(nullptr)
173{ }
174
175AmdGPUBinGenerator::AmdGPUBinGenerator(const AmdInput* amdInput)
176        : manageable(false), input(amdInput)
177{ }
178
179AmdGPUBinGenerator::AmdGPUBinGenerator(bool _64bitMode, GPUDeviceType deviceType,
180       uint32_t driverVersion, size_t globalDataSize, const cxbyte* globalData,
181       const std::vector<AmdKernelInput>& kernelInputs)
182        : manageable(true), input(nullptr)
183{
184    input = new AmdInput{_64bitMode, deviceType, globalDataSize, globalData,
185                driverVersion, "", "", kernelInputs };
186}
187
188AmdGPUBinGenerator::AmdGPUBinGenerator(bool _64bitMode, GPUDeviceType deviceType,
189       uint32_t driverVersion, size_t globalDataSize, const cxbyte* globalData,
190       std::vector<AmdKernelInput>&& kernelInputs)
191        : manageable(true), input(nullptr)
192{
193    input = new AmdInput{_64bitMode, deviceType, globalDataSize, globalData,
194                driverVersion, "", "", std::move(kernelInputs) };
195}
196
197AmdGPUBinGenerator::~AmdGPUBinGenerator()
198{
199    if (manageable)
200        delete input;
201}
202
203void AmdGPUBinGenerator::setInput(const AmdInput* input)
204{
205    if (manageable)
206        delete input;
207    manageable = false;
208    this->input = input;
209}
210
211static const char* imgTypeNamesTable[] = { "2D", "1D", "1DA", "1DB", "2D", "2DA", "3D" };
212
213static const cxuint imgUavDimTable[] = { 2, 1, 0, 0, 2, 2, 3 };
214
215enum KindOfType : cxbyte
216{
217    KT_UNSIGNED = 0,
218    KT_SIGNED,
219    KT_FLOAT,
220    KT_DOUBLE,
221    KT_STRUCT,
222    KT_UNKNOWN
223};
224
225struct CLRX_INTERNAL TypeNameVecSize
226{
227    const char* name;
228    KindOfType kindOfType;
229    cxbyte elemSize;
230    cxbyte vecSize;
231};
232
233static const TypeNameVecSize argTypeNamesTable[] =
234{
235    { "u8", KT_UNSIGNED, 1, 1 }, // VOID
236    { "u8", KT_UNSIGNED, 1, 1 }, { "i8", KT_SIGNED, 1, 1 },
237    { "u16", KT_UNSIGNED, 2, 1 }, { "i16", KT_SIGNED, 2, 1 },
238    { "u32", KT_UNSIGNED, 4, 1 }, { "i32", KT_SIGNED, 4, 1 },
239    { "u64", KT_UNSIGNED, 8, 1 }, { "i64", KT_SIGNED, 8, 1 },
240    { "float", KT_FLOAT, 4, 1 }, { "double", KT_DOUBLE, 8, 1 },
241    { nullptr, KT_UNKNOWN, 1, 1 }, // POINTER
242    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE
243    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE1D
244    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE1D_ARRAY
245    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE1D_BUFFER
246    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE2D
247    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE1D_ARRAY
248    { nullptr, KT_UNKNOWN, 1, 1 }, // IMAGE3D
249    { "u8", KT_UNSIGNED, 1, 2 }, { "u8", KT_UNSIGNED, 1, 3 }, { "u8", KT_UNSIGNED, 1, 4 },
250    { "u8",KT_UNSIGNED, 1, 8 }, { "u8", KT_UNSIGNED, 1, 16 },
251    { "i8", KT_SIGNED, 1, 2 }, { "i8", KT_SIGNED, 1, 3 }, { "i8", KT_SIGNED, 1, 4 },
252    { "i8", KT_SIGNED, 1, 8 }, { "i8", KT_SIGNED, 1, 16 },
253    { "u16", KT_UNSIGNED, 2, 2 }, { "u16", KT_UNSIGNED, 2, 3 },
254    { "u16", KT_UNSIGNED, 2, 4 }, { "u16", KT_UNSIGNED, 2, 8 },
255    { "u16", KT_UNSIGNED, 2, 16 },
256    { "i16", KT_SIGNED, 2, 2 }, { "i16", KT_SIGNED, 2, 3 },
257    { "i16", KT_SIGNED, 2, 4 }, { "i16", KT_SIGNED, 2, 8 },
258    { "i16", KT_SIGNED, 2, 16 },
259    { "u32", KT_UNSIGNED, 4, 2 }, { "u32", KT_UNSIGNED, 4, 3 },
260    { "u32", KT_UNSIGNED, 4, 4 }, { "u32", KT_UNSIGNED, 4, 8 },
261    { "u32", KT_UNSIGNED, 4, 16 },
262    { "i32", KT_SIGNED, 4, 2 }, { "i32", KT_SIGNED, 4, 3 },
263    { "i32", KT_SIGNED, 4, 4 }, { "i32", KT_SIGNED, 4, 8 },
264    { "i32", KT_SIGNED, 4, 16 },
265    { "u64", KT_UNSIGNED, 8, 2 }, { "u64", KT_UNSIGNED, 8, 3 },
266    { "u64", KT_UNSIGNED, 8, 4 }, { "u64", KT_UNSIGNED, 8, 8 },
267    { "u64", KT_UNSIGNED, 8, 16 },
268    { "i64", KT_SIGNED, 8, 2 }, { "i64", KT_SIGNED, 8, 3 },
269    { "i64", KT_SIGNED, 8, 4 }, { "i64", KT_SIGNED, 8, 8 },
270    { "i64", KT_SIGNED, 8, 16 },
271    { "float", KT_FLOAT, 4, 2 }, { "float", KT_FLOAT, 4, 3 },
272    { "float", KT_FLOAT, 4, 4 }, { "float", KT_FLOAT, 4, 8 },
273    { "float", KT_FLOAT, 4, 16 },
274    { "double", KT_DOUBLE, 8, 2 }, { "double", KT_DOUBLE, 8, 3 },
275    { "double", KT_DOUBLE, 8, 4 }, { "double", KT_DOUBLE, 8, 8 },
276    { "double", KT_DOUBLE, 8, 16 },
277    { "u32", KT_UNSIGNED, 4, 1 }, /* SAMPLER */ { "struct", KT_STRUCT, 0, 1 },
278    { nullptr, KT_UNKNOWN, 1, 1 }, /* COUNTER32 */
279    { nullptr, KT_UNKNOWN, 1, 1 } // COUNTER64
280};
281
282/// temporary kernel configuration. holds resolved resource ids values and other setup
283struct CLRX_INTERNAL TempAmdKernelConfig
284{
285    uint32_t hwRegion;
286    uint32_t uavPrivate;
287    uint32_t uavId;
288    uint32_t constBufferId;
289    uint32_t printfId;
290    uint32_t privateId;
291    uint32_t argsSpace;
292    Array<uint16_t> argResIds;
293    uint32_t uavsNum;
294    uint32_t calNotesSize;
295};
296
297
298static const uint16_t mainBuiltinSectionTable[] =
299{
300    1, // ELFSECTID_SHSTRTAB
301    2, // ELFSECTID_STRTAB
302    3, // ELFSECTID_SYMTAB
303    SHN_UNDEF, // ELFSECTID_DYNSTR
304    SHN_UNDEF, // ELFSECTID_DYNSYM
305    5, // ELFSECTID_TEXT
306    4, // ELFSECTID_RODATA
307    SHN_UNDEF, // ELFSECTID_DATA
308    SHN_UNDEF, // ELFSECTID_BSS
309    6 // ELFSECTID_COMMENT
310};
311
312static const uint16_t emptyMainBuiltinSectionTable[] =
313{
314    1, // ELFSECTID_SHSTRTAB
315    2, // ELFSECTID_STRTAB
316    3, // ELFSECTID_SYMTAB
317    SHN_UNDEF, // ELFSECTID_DYNSTR
318    SHN_UNDEF, // ELFSECTID_DYNSYM
319    SHN_UNDEF, // ELFSECTID_TEXT
320    SHN_UNDEF, // ELFSECTID_RODATA
321    SHN_UNDEF, // ELFSECTID_DATA
322    SHN_UNDEF, // ELFSECTID_BSS
323    4 // ELFSECTID_COMMENT
324};
325
326static const uint16_t kernelBuiltinSectionTable[] =
327{
328    1, // ELFSECTID_SHSTRTAB
329    5, // ELFSECTID_STRTAB
330    4, // ELFSECTID_SYMTAB
331    SHN_UNDEF, // ELFSECTID_DYNSTR
332    SHN_UNDEF, // ELFSECTID_DYNSYM
333    2, // ELFSECTID_TEXT
334    SHN_UNDEF, // ELFSECTID_RODATA
335    3, // ELFSECTID_DATA
336    SHN_UNDEF, // ELFSECTID_BSS
337    SHN_UNDEF // ELFSECTID_COMMENT
338};
339
340static void generateCALNotes(FastOutputBuffer& bos, const AmdInput* input,
341         cxuint driverVersion, const AmdKernelInput& kernel,
342         const TempAmdKernelConfig& tempConfig);
343
344class CLRX_INTERNAL CALNoteGen: public ElfRegionContent
345{
346private:
347    const AmdInput* input;
348    cxuint driverVersion;
349    const AmdKernelInput* kernel;
350    const TempAmdKernelConfig* tempConfig;
351public:
352    CALNoteGen() { }
353    CALNoteGen(const AmdInput* _input, cxuint _driverVersion,
354           const AmdKernelInput* _kernel, const TempAmdKernelConfig* _tempConfig)
355        : input(_input), driverVersion(_driverVersion), kernel(_kernel),
356          tempConfig(_tempConfig)
357    { }
358   
359    void operator()(FastOutputBuffer& fob) const
360    {
361        if (kernel->useConfig)
362            generateCALNotes(fob, input, driverVersion, *kernel, *tempConfig);
363        else
364            for (const CALNoteInput& calNote: kernel->calNotes)
365            {   // all fields of CALNote
366                CALNoteHeader cnHdr = { LEV(calNote.header.nameSize),
367                    LEV(calNote.header.descSize), LEV(calNote.header.type) };
368                ::memcpy(cnHdr.name, &calNote.header.name, 8);
369                fob.writeObject(cnHdr);
370                fob.writeArray(calNote.header.descSize, calNote.data);
371            }
372    }
373};
374
375class CLRX_INTERNAL KernelDataGen: public ElfRegionContent
376{
377private:
378    const AmdKernelInput* kernel;
379public:
380    KernelDataGen() { }
381    KernelDataGen(const AmdKernelInput* _kernel) : kernel(_kernel)
382    { }
383   
384    void operator()(FastOutputBuffer& fob) const
385    {
386        if (kernel->data!=nullptr)
387            fob.writeArray(kernel->dataSize, kernel->data);
388        else
389            fob.fill(4736, 0);
390    }
391};
392
393struct CLRX_INTERNAL TempAmdKernelData
394{
395    uint32_t innerBinSize;
396    std::string metadata;
397    CALNoteGen calNoteGen;
398    KernelDataGen kernelDataGen;
399    ElfBinaryGen32 elfBinGen; // for kernel
400    CALEncodingEntry calEncEntry;
401    uint32_t header[8];
402};
403
404// fast and memory efficient String table generator for main binary
405class CLRX_INTERNAL CL1MainStrTabGen: public ElfRegionContent
406{
407private:
408    cxuint driverVersion;
409    const AmdInput* input;
410public:
411    CL1MainStrTabGen(cxuint _driverVersion, const AmdInput* _input)
412            : driverVersion(_driverVersion), input(_input)
413    { }
414   
415    size_t size() const
416    {
417        size_t size = 1;
418        if (!input->compileOptions.empty())
419            size += 25;
420        if (input->globalData != nullptr)
421            size += 18;
422       
423        for (const AmdKernelInput& kernel: input->kernels)
424            size += kernel.kernelName.size()*3 + 19 + 17 + 17;
425        for (const BinSymbol& symbol: input->extraSymbols)
426            size += symbol.name.size()+1;
427        return size;
428    }
429   
430    void operator()(FastOutputBuffer& fob) const
431    {
432        const bool isOlderThan1348 = driverVersion < 134805;
433        fob.put(0);
434        if (!input->compileOptions.empty())
435            fob.write(25, "__OpenCL_compile_options");
436        if (input->globalData != nullptr)
437            fob.write(18, (!isOlderThan1348)?"__OpenCL_0_global":"__OpenCL_2_global");
438       
439        for (const AmdKernelInput& kernel: input->kernels)
440        {
441            fob.write(9, "__OpenCL_");
442            fob.write(kernel.kernelName.size(), kernel.kernelName.c_str());
443            fob.write(19, "_metadata\000__OpenCL_");
444            fob.write(kernel.kernelName.size(), kernel.kernelName.c_str());
445            fob.write(17, "_kernel\000__OpenCL_");
446            fob.write(kernel.kernelName.size(), kernel.kernelName.c_str());
447            fob.write(8, "_header");
448        }
449        for (const BinSymbol& symbol: input->extraSymbols)
450            fob.write(symbol.name.size()+1, symbol.name.c_str());
451    }
452};
453
454// fast and memory efficient symbol table generator for main binary
455template<typename Types>
456class CLRX_INTERNAL CL1MainSymTabGen: public ElfRegionContent
457{
458private:
459    cxuint driverVersion;
460    const AmdInput* input;
461    const Array<TempAmdKernelData>& tempDatas;
462public:
463    CL1MainSymTabGen(cxuint _driverVersion, const AmdInput* _input,
464                  const Array<TempAmdKernelData>& _tempDatas)
465            : driverVersion(_driverVersion), input(_input), tempDatas(_tempDatas)
466    { }
467   
468    size_t size() const
469    {
470        return sizeof(typename Types::Sym)*(1 + (!input->compileOptions.empty()) +
471                (input->globalData != nullptr) + 3*input->kernels.size() +
472                input->extraSymbols.size());
473    }
474   
475    void operator()(FastOutputBuffer& fob) const
476    {
477        const uint16_t* mainSectTable = input->kernels.empty() ?
478                emptyMainBuiltinSectionTable : mainBuiltinSectionTable;
479        const cxuint extraSectId = input->kernels.empty() ? 5 : 7;
480       
481        fob.fill(sizeof(typename Types::Sym), 0);
482        typename Types::Sym sym;
483        size_t nameOffset = 1;
484        if (!input->compileOptions.empty())
485        {
486            SLEV(sym.st_name, nameOffset);
487            SLEV(sym.st_shndx, uint16_t((input->kernels.size()!=0)?6:4));
488            SLEV(sym.st_value, 0);
489            SLEV(sym.st_size, input->compileOptions.size());
490            sym.st_info = ELF32_ST_INFO(STB_LOCAL, STT_OBJECT);
491            sym.st_other = 0;
492            nameOffset += 25;
493            fob.writeObject(sym);
494        }
495        size_t rodataPos = 0;
496        if (input->globalData != nullptr)
497        {
498            SLEV(sym.st_name, nameOffset);
499            SLEV(sym.st_shndx, 4);
500            SLEV(sym.st_value, 0);
501            SLEV(sym.st_size, input->globalDataSize);
502            sym.st_info = ELF32_ST_INFO(STB_LOCAL, STT_OBJECT);
503            sym.st_other = 0;
504            nameOffset += 18;
505            fob.writeObject(sym);
506            rodataPos += input->globalDataSize;
507        }
508       
509        size_t textPos = 0;
510        for (size_t i = 0; i < input->kernels.size(); i++)
511        {
512            const AmdKernelInput& kernel = input->kernels[i];
513            // metadata
514            const size_t metadataSize = (kernel.useConfig) ?
515                    tempDatas[i].metadata.size() : kernel.metadataSize;
516            SLEV(sym.st_name, nameOffset);
517            SLEV(sym.st_shndx, 4);
518            SLEV(sym.st_size, metadataSize);
519            SLEV(sym.st_value, rodataPos);
520            sym.st_info = ELF32_ST_INFO(STB_LOCAL, STT_OBJECT);
521            sym.st_other = 0;
522            fob.writeObject(sym);
523            nameOffset += kernel.kernelName.size() + 19;
524            rodataPos += metadataSize;
525            // kernel
526            SLEV(sym.st_name, nameOffset);
527            SLEV(sym.st_shndx, 5);
528            SLEV(sym.st_size, tempDatas[i].innerBinSize);
529            SLEV(sym.st_value, textPos);
530            sym.st_info = ELF32_ST_INFO(STB_LOCAL, STT_FUNC);
531            sym.st_other = 0;
532            fob.writeObject(sym);
533            nameOffset += kernel.kernelName.size() + 17;
534            textPos += tempDatas[i].innerBinSize;
535            // kernel
536            const size_t headerSize = (kernel.useConfig) ? 32 : kernel.headerSize;
537            SLEV(sym.st_name, nameOffset);
538            SLEV(sym.st_shndx, 4);
539            SLEV(sym.st_size, headerSize);
540            SLEV(sym.st_value, rodataPos);
541            sym.st_info = ELF32_ST_INFO(STB_LOCAL, STT_OBJECT);
542            sym.st_other = 0;
543            fob.writeObject(sym);
544            nameOffset += kernel.kernelName.size() + 17;
545            rodataPos += headerSize;
546        }
547       
548        for (const BinSymbol& symbol: input->extraSymbols)
549        {
550            SLEV(sym.st_name, nameOffset);
551            SLEV(sym.st_shndx, convertSectionId(symbol.sectionId, mainSectTable,
552                            ELFSECTID_STD_MAX, extraSectId));
553            SLEV(sym.st_size, symbol.size);
554            SLEV(sym.st_value, symbol.value);
555            sym.st_info = symbol.info;
556            sym.st_other = symbol.other;
557            nameOffset += symbol.name.size()+1;
558            fob.writeObject(sym);
559        }
560    }
561};
562
563class CLRX_INTERNAL CL1MainRoDataGen: public ElfRegionContent
564{
565private:
566    const AmdInput* input;
567    const Array<TempAmdKernelData>& tempDatas;
568public:
569    CL1MainRoDataGen(const AmdInput* _input, const Array<TempAmdKernelData>& _tempDatas)
570            : input(_input), tempDatas(_tempDatas)
571    { }
572   
573    void operator()(FastOutputBuffer& fob) const
574    {
575        if (input->globalData != nullptr)
576            fob.writeArray(input->globalDataSize, input->globalData);
577        for (size_t i = 0; i < input->kernels.size(); i++)
578        {
579            const AmdKernelInput& kernel = input->kernels[i];
580            if (kernel.useConfig)
581            {
582                fob.write(tempDatas[i].metadata.size(), tempDatas[i].metadata.c_str());
583                fob.writeArray(8, tempDatas[i].header);
584            }
585            else
586            {
587                fob.write(kernel.metadataSize, kernel.metadata);
588                fob.writeArray(kernel.headerSize, kernel.header);
589            }
590        }
591    }
592};
593
594class CLRX_INTERNAL CL1MainTextGen: public ElfRegionContent
595{
596private:
597    Array<TempAmdKernelData>& tempDatas;
598public:
599    CL1MainTextGen(Array<TempAmdKernelData>& _tempDatas) : tempDatas(_tempDatas)
600    { }
601   
602    void operator()(FastOutputBuffer& fob) const
603    {
604        for (TempAmdKernelData& kernel: tempDatas)
605            kernel.elfBinGen.generate(fob);
606    }
607};
608
609class CLRX_INTERNAL CL1MainCommentGen: public ElfRegionContent
610{
611private:
612    const AmdInput* input;
613    const CString& driverInfo;
614public:
615    CL1MainCommentGen(const AmdInput* _input, const CString& _driverInfo)
616            : input(_input), driverInfo(_driverInfo)
617    { }
618   
619    void operator()(FastOutputBuffer& fob) const
620    {
621        fob.write(input->compileOptions.size(), input->compileOptions.c_str());
622        fob.write(driverInfo.size(), driverInfo.c_str());
623    }
624};
625
626template<typename Types>
627static void putMainSections(ElfBinaryGenTemplate<Types>& elfBinGen, cxuint driverVersion,
628        const AmdInput* input, size_t allInnerBinSize, const CL1MainTextGen& textGen,
629        size_t rodataSize, const CL1MainRoDataGen& rodataGen, const CString& driverInfo,
630        const CL1MainCommentGen& commentGen, const CL1MainStrTabGen& mainStrGen,
631        const CL1MainSymTabGen<Types>& mainSymGen)
632{
633    const uint16_t* mainSectTable = input->kernels.empty() ?
634            emptyMainBuiltinSectionTable : mainBuiltinSectionTable;
635    const cxuint extraSectId = input->kernels.empty() ? 5 : 7;
636   
637    elfBinGen.addRegion(ElfRegionTemplate<Types>(0, (const cxbyte*)nullptr, 1,
638                 ".shstrtab", SHT_STRTAB, SHF_STRINGS));
639    elfBinGen.addRegion(ElfRegionTemplate<Types>(mainStrGen.size(), &mainStrGen, 1,
640                 ".strtab", SHT_STRTAB, SHF_STRINGS));
641    elfBinGen.addRegion(ElfRegionTemplate<Types>(mainSymGen.size(), &mainSymGen, 8,
642                 ".symtab", SHT_SYMTAB, 0));
643    if (!input->kernels.empty())
644    {   // rodata and text
645        elfBinGen.addRegion(ElfRegionTemplate<Types>(rodataSize, &rodataGen, 1,
646                 ".rodata", SHT_PROGBITS, SHF_ALLOC));
647        elfBinGen.addRegion(ElfRegionTemplate<Types>(allInnerBinSize, &textGen, 1,
648                ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR));
649    }
650    // comment
651    elfBinGen.addRegion(ElfRegionTemplate<Types>(
652                input->compileOptions.size()+driverInfo.size(), &commentGen, 1,
653                ".comment", SHT_PROGBITS, 0));
654    for (const BinSection& section: input->extraSections)
655        elfBinGen.addRegion(ElfRegionTemplate<Types>(section, mainSectTable,
656                         ELFSECTID_STD_MAX, extraSectId));
657    elfBinGen.addRegion(ElfRegionTemplate<Types>::sectionHeaderTable());
658}
659
660/* perform some checkings for resource ids and fill resource ids and other that was set
661 * as default. store that setup in TempAndKernelConfig */
662static void prepareTempConfigs(cxuint driverVersion, const AmdInput* input,
663       Array<TempAmdKernelConfig>& tempAmdKernelConfigs)
664{
665    const bool isOlderThan1348 = driverVersion < 134805;
666    const bool isOlderThan1598 = driverVersion < 159805;
667   
668    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
669    cxuint maxSGPRSNum = getGPUMaxRegistersNum(arch, REGTYPE_SGPR, REGCOUNT_NO_VCC);
670    cxuint maxVGPRSNum = getGPUMaxRegistersNum(arch, REGTYPE_VGPR, 0);
671   
672    for (size_t i = 0; i < input->kernels.size(); i++)
673    {
674        const AmdKernelInput& kinput = input->kernels[i];
675        if (!kinput.useConfig)
676        {
677            if (kinput.metadata == nullptr || kinput.metadataSize == 0)
678                throw Exception("No metadata for kernel");
679            if (kinput.header == nullptr || kinput.headerSize == 0)
680                throw Exception("No header for kernel");
681            if (kinput.code == nullptr)
682                throw Exception("No code for kernel");
683            continue; // and skip
684        }
685        const AmdKernelConfig& config = kinput.config;
686        TempAmdKernelConfig& tempConfig = tempAmdKernelConfigs[i];
687        if (config.userDatas.size() > 16)
688            throw Exception("UserDataElemsNum must not be greater than 16");
689        if (config.usedVGPRsNum > maxVGPRSNum)
690            throw Exception("Used VGPRs number out of range");
691        if (config.usedSGPRsNum > maxSGPRSNum)
692            throw Exception("Used SGPRs number out of range");
693        if (config.hwLocalSize > 32768)
694            throw Exception("HWLocalSize out of range");
695        if (config.floatMode >= 256)
696            throw Exception("FloatMode out of range");
697       
698        /* filling input */
699        if (config.hwRegion == BINGEN_DEFAULT)
700            tempConfig.hwRegion = 0;
701        else
702            tempConfig.hwRegion = config.hwRegion;
703       
704        /* checking arg types */
705        for (const AmdKernelArgInput& arg: config.args)
706            if (arg.argType > KernelArgType::MAX_VALUE)
707                throw Exception("Unknown argument type");
708            else if (arg.argType == KernelArgType::POINTER)
709            {
710                if (arg.pointerType > KernelArgType::MAX_VALUE)
711                    throw Exception("Unknown argument's pointer type");
712                if (arg.ptrSpace > KernelPtrSpace::MAX_VALUE ||
713                    arg.ptrSpace == KernelPtrSpace::NONE)
714                    throw Exception("Wrong pointer space type");
715            }
716            else if (isKernelArgImage(arg.argType))
717            {
718                if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == 0)
719                    throw Exception("Invalid access qualifier for image");
720            }
721       
722        if (config.uavPrivate == BINGEN_DEFAULT)
723        {   /* compute uavPrivate */
724            bool hasStructures = false;
725            uint32_t amountOfArgs = 0;
726            for (const AmdKernelArgInput& arg: config.args)
727            {
728                if (arg.argType == KernelArgType::STRUCTURE ||
729                    arg.argType == KernelArgType::COUNTER32)
730                    hasStructures = true;
731                if (!isOlderThan1598 && arg.argType != KernelArgType::STRUCTURE)
732                    continue; // no older driver and no structure
733                if (arg.argType == KernelArgType::POINTER)
734                    amountOfArgs += 32;
735                else if (arg.argType == KernelArgType::STRUCTURE)
736                {
737                    if (!isOlderThan1598)
738                        amountOfArgs += (arg.structSize+15)&~15;
739                    else // bug in older drivers
740                        amountOfArgs += 32;
741                }
742                else
743                {
744                    const TypeNameVecSize& tp = argTypeNamesTable[cxuint(arg.argType)];
745                    const size_t typeSize = cxuint(tp.vecSize==3?4:tp.vecSize)*tp.elemSize;
746                    amountOfArgs += ((typeSize+15)>>4)<<5;
747                }
748            }
749           
750            tempConfig.uavPrivate = (hasStructures) ? amountOfArgs : 0;
751            if (tempConfig.uavPrivate < config.scratchBufferSize)
752                tempConfig.uavPrivate = config.scratchBufferSize;
753        }
754        else
755            tempConfig.uavPrivate = config.uavPrivate;
756       
757        if (config.uavId == BINGEN_DEFAULT)
758        {
759            if (driverVersion < 134805 || driverVersion > 144505)
760                tempConfig.uavId = (isOlderThan1348)?9:11;
761            else
762            {
763                bool hasPointer = false;
764                for (const AmdKernelArgInput& arg: config.args)
765                    if (arg.argType == KernelArgType::POINTER &&
766                        (arg.ptrSpace == KernelPtrSpace::CONSTANT ||
767                         arg.ptrSpace == KernelPtrSpace::GLOBAL))
768                        hasPointer = true;
769               
770                tempConfig.uavId = (hasPointer || config.usePrintf)?11:BINGEN_NOTSUPPLIED;
771            }
772        }
773        else
774            tempConfig.uavId = config.uavId;
775       
776        if (config.constBufferId == BINGEN_DEFAULT)
777            tempConfig.constBufferId = (isOlderThan1348)?BINGEN_NOTSUPPLIED : 10;
778        else
779            tempConfig.constBufferId = config.constBufferId;
780       
781        if (config.printfId == BINGEN_DEFAULT)
782            tempConfig.printfId = (!isOlderThan1348 &&
783                (driverVersion >= 152603 || config.usePrintf)) ? 9 : BINGEN_NOTSUPPLIED;
784        else
785            tempConfig.printfId = config.printfId;
786       
787        if (config.privateId == BINGEN_DEFAULT)
788            tempConfig.privateId = 8;
789        else
790            tempConfig.privateId = config.privateId;
791       
792        if (tempConfig.uavId != BINGEN_NOTSUPPLIED && tempConfig.uavId >= 1024)
793            throw Exception("UavId out of range");
794        if (tempConfig.constBufferId != BINGEN_NOTSUPPLIED &&
795            tempConfig.constBufferId >= 1024)
796            throw Exception("ConstBufferId out of range");
797        if (tempConfig.printfId != BINGEN_NOTSUPPLIED && tempConfig.printfId >= 1024)
798            throw Exception("PrintfId out of range");
799        if (tempConfig.privateId != BINGEN_NOTSUPPLIED && tempConfig.privateId >= 1024)
800            throw Exception("PrivateId out of range");
801       
802        /* fill argUavIds for global/constant pointers */
803        cxuint puavIdsCount = tempConfig.uavId+1;
804        std::bitset<1024> puavMask;
805        cxuint cntIdsCount = 0;
806        std::bitset<8> cntIdMask;
807        cxuint cbIdsCount = 2 + (input->globalData != nullptr);
808        std::bitset<160> cbIdMask;
809        cxuint rdImgsCount = 0;
810        std::bitset<128> rdImgMask;
811        cxuint wrImgsCount = 0;
812        std::bitset<8> wrImgMask;
813        tempConfig.argResIds.resize(config.args.size());
814       
815        for (cxuint k = 0; k < config.args.size(); k++)
816        {
817            const AmdKernelArgInput& arg = config.args[k];
818            if (arg.argType == KernelArgType::POINTER &&
819                (arg.ptrSpace == KernelPtrSpace::GLOBAL ||
820                 (arg.ptrSpace == KernelPtrSpace::CONSTANT && !isOlderThan1348)) &&
821               arg.resId != BINGEN_DEFAULT)
822            {
823                if ((arg.resId < 9 && arg.used) ||
824                    (!arg.used && arg.resId != tempConfig.uavId) || arg.resId >= 1024)
825                    throw Exception("UavId out of range!");
826                if (puavMask[arg.resId] && arg.resId != tempConfig.uavId)
827                    throw Exception("UavId already used!");
828                puavMask.set(arg.resId);
829                tempConfig.argResIds[k] = arg.resId;
830            }
831            else if (arg.argType == KernelArgType::POINTER &&
832                    arg.ptrSpace == KernelPtrSpace::CONSTANT && arg.resId != BINGEN_DEFAULT)
833            {   // old constant buffers
834                if (arg.resId < 2 || arg.resId >= 160)
835                    throw Exception("CbId out of range!");
836                if (cbIdMask[arg.resId])
837                    throw Exception("CbId already used!");
838                cbIdMask.set(arg.resId);
839                tempConfig.argResIds[k] = arg.resId;
840            }
841            else if (isKernelArgImage(arg.argType) && arg.resId != BINGEN_DEFAULT)
842            {   // images
843                if (arg.ptrAccess & KARG_PTR_READ_ONLY)
844                {
845                    if (arg.resId >= 128)
846                        throw Exception("RdImgId out of range!");
847                    if (rdImgMask[arg.resId])
848                        throw Exception("RdImgId already used!");
849                    rdImgMask.set(arg.resId);
850                    tempConfig.argResIds[k] = arg.resId;
851                }
852                else if (arg.ptrAccess & KARG_PTR_WRITE_ONLY)
853                {
854                    if (arg.resId >= 8)
855                        throw Exception("WrImgId out of range!");
856                    if (wrImgMask[arg.resId])
857                        throw Exception("WrImgId already used!");
858                    wrImgMask.set(arg.resId);
859                    tempConfig.argResIds[k] = arg.resId;
860                }
861            }
862            else if (arg.argType == KernelArgType::COUNTER32 && arg.resId != BINGEN_DEFAULT)
863            {
864                if (arg.resId >= 8)
865                    throw Exception("CounterId out of range!");
866                if (cntIdMask[arg.resId])
867                    throw Exception("CounterId already used!");
868                cntIdMask.set(arg.resId);
869                tempConfig.argResIds[k] = arg.resId;
870            }
871        }
872       
873        for (cxuint k = 0; k < config.args.size(); k++)
874        {
875            const AmdKernelArgInput& arg = config.args[k];
876            if (arg.argType == KernelArgType::POINTER &&
877                (arg.ptrSpace == KernelPtrSpace::GLOBAL ||
878                 (arg.ptrSpace == KernelPtrSpace::CONSTANT && !isOlderThan1348)) &&
879                arg.resId == BINGEN_DEFAULT)
880            {
881                if (arg.used)
882                {
883                    for (; puavIdsCount < 1024 && puavMask[puavIdsCount];
884                         puavIdsCount++);
885                    if (puavIdsCount == 1024)
886                        throw Exception("UavId out of range!");
887                    tempConfig.argResIds[k] = puavIdsCount++;
888                }
889                else // use unused uavId (9 or 11)
890                    tempConfig.argResIds[k] = tempConfig.uavId;
891            }
892            else if (arg.argType == KernelArgType::POINTER &&
893                    arg.ptrSpace == KernelPtrSpace::CONSTANT && arg.resId == BINGEN_DEFAULT)
894            {   // old constant buffers
895                for (; cbIdsCount < 160 && cbIdMask[cbIdsCount]; cbIdsCount++);
896                if (cbIdsCount == 160)
897                    throw Exception("CbId out of range!");
898                tempConfig.argResIds[k] = cbIdsCount++;
899            }
900            else if (isKernelArgImage(arg.argType) && arg.resId == BINGEN_DEFAULT)
901            {   // images
902                if (arg.ptrAccess & KARG_PTR_READ_ONLY)
903                {
904                    for (; rdImgsCount < 128 && rdImgMask[rdImgsCount]; rdImgsCount++);
905                    if (rdImgsCount == 128)
906                        throw Exception("RdImgId out of range!");
907                    tempConfig.argResIds[k] = rdImgsCount++;
908                }
909                else if (arg.ptrAccess & KARG_PTR_WRITE_ONLY)
910                {
911                    for (; wrImgsCount < 8 && wrImgMask[wrImgsCount]; wrImgsCount++);
912                    if (wrImgsCount == 8)
913                        throw Exception("WrImgId out of range!");
914                    tempConfig.argResIds[k] = wrImgsCount++;
915                }
916            }
917            else if (arg.argType == KernelArgType::COUNTER32 && arg.resId == BINGEN_DEFAULT)
918            {
919                for (; cntIdsCount < 8 && cntIdMask[cntIdsCount]; cntIdsCount++);
920                if (cntIdsCount == 8)
921                    throw Exception("CounterId out of range!");
922                tempConfig.argResIds[k] = cntIdsCount++;
923            }
924        }
925    }
926}
927
928static std::string generateMetadata(cxuint driverVersion, const AmdInput* input,
929        const AmdKernelInput& kinput, TempAmdKernelConfig& tempConfig,
930        cxuint argSamplersNum, cxuint uniqueId)
931{
932    const bool isOlderThan1124 = driverVersion < 112402;
933    const bool isOlderThan1348 = driverVersion < 134805;
934    const AmdKernelConfig& config = kinput.config;
935    /* compute metadataSize */
936    std::string metadata;
937    metadata.reserve(100);
938    metadata += ";ARGSTART:__OpenCL_";
939    metadata += kinput.kernelName.c_str();
940    metadata += "_kernel\n";
941    if (isOlderThan1124)
942        metadata += ";version:3:1:104\n";
943    else
944        metadata += ";version:3:1:111\n";
945    metadata += ";device:";
946    const char* devName = getGPUDeviceTypeName(input->deviceType);
947    while (*devName != 0) // dev name must be in lower letter
948        metadata += ::tolower(*devName++);
949    char numBuf[21];
950    metadata += "\n;uniqueid:";
951    itocstrCStyle(uniqueId, numBuf, 21);
952    metadata += numBuf;
953    metadata += "\n;memory:uavprivate:";
954    itocstrCStyle(tempConfig.uavPrivate, numBuf, 21);
955    metadata += numBuf;
956    metadata += "\n;memory:hwlocal:";
957    itocstrCStyle(config.hwLocalSize, numBuf, 21);
958    metadata += numBuf;
959    metadata += "\n;memory:hwregion:";
960    itocstrCStyle(tempConfig.hwRegion, numBuf, 21);
961    metadata += numBuf;
962    metadata += '\n';
963    /* reqd_work_group_size for kernel (cws) */
964    if (config.reqdWorkGroupSize[0] != 0 || config.reqdWorkGroupSize[1] != 0 ||
965        config.reqdWorkGroupSize[1] != 0)
966    {
967        metadata += ";cws:";
968        itocstrCStyle(config.reqdWorkGroupSize[0], numBuf, 21);
969        metadata += numBuf;
970        metadata += ':';
971        itocstrCStyle(config.reqdWorkGroupSize[1], numBuf, 21);
972        metadata += numBuf;
973        metadata += ':';
974        itocstrCStyle(config.reqdWorkGroupSize[2], numBuf, 21);
975        metadata += numBuf;
976        metadata += '\n';
977    }
978   
979    size_t argOffset = 0;
980    /* put kernel arg info to metadata */
981    for (cxuint k = 0; k < config.args.size(); k++)
982    {
983        const AmdKernelArgInput& arg = config.args[k];
984        if (arg.argType == KernelArgType::STRUCTURE)
985        {
986            metadata += ";value:";
987            metadata += arg.argName.c_str();
988            metadata += ":struct:";
989            itocstrCStyle(arg.structSize, numBuf, 21);
990            metadata += numBuf;
991            metadata += ":1:";
992            itocstrCStyle(argOffset, numBuf, 21);
993            metadata += numBuf;
994            metadata += '\n';
995            argOffset += (arg.structSize+15)&~15;
996        }
997        else if (arg.argType == KernelArgType::POINTER)
998        {
999            metadata += ";pointer:";
1000            metadata += arg.argName.c_str();
1001            metadata += ':';
1002            const TypeNameVecSize& tp = argTypeNamesTable[cxuint(arg.pointerType)];
1003            if (tp.kindOfType == KT_UNKNOWN)
1004                throw Exception("Type not supported!");
1005            const cxuint typeSize =
1006                cxuint((tp.vecSize==3) ? 4 : tp.vecSize)*tp.elemSize;
1007            if (arg.structSize == 0 && arg.pointerType == KernelArgType::STRUCTURE)
1008                metadata += "opaque"; // opaque indicates pointer to structure
1009            else
1010                metadata += tp.name;
1011            metadata += ":1:1:";
1012            itocstrCStyle(argOffset, numBuf, 21);
1013            metadata += numBuf;
1014            metadata += ':';
1015            if (arg.ptrSpace == KernelPtrSpace::LOCAL)
1016            {
1017                metadata += "hl:";
1018                itocstrCStyle((arg.resId!=BINGEN_DEFAULT)?arg.resId:1, numBuf, 21);
1019                metadata += numBuf;
1020            }
1021            else if (arg.ptrSpace == KernelPtrSpace::CONSTANT ||
1022                     arg.ptrSpace == KernelPtrSpace::GLOBAL)
1023            {
1024                if (arg.ptrSpace == KernelPtrSpace::GLOBAL)
1025                    metadata += "uav:";
1026                else
1027                    metadata += (isOlderThan1348)?"hc:":"c:";
1028                itocstrCStyle(tempConfig.argResIds[k], numBuf, 21);
1029                metadata += numBuf;
1030            }
1031            else
1032                throw Exception("Other memory spaces are not supported");
1033            metadata += ':';
1034            const size_t elemSize = (arg.pointerType==KernelArgType::STRUCTURE)?
1035                ((arg.structSize!=0)?arg.structSize:4) : typeSize;
1036            itocstrCStyle(elemSize, numBuf, 21);
1037            metadata += numBuf;
1038            metadata += ':';
1039            metadata += ((arg.ptrAccess & KARG_PTR_CONST) ||
1040                    arg.ptrSpace == KernelPtrSpace::CONSTANT)?"RO":"RW";
1041            metadata += ':';
1042            metadata += (arg.ptrAccess & KARG_PTR_VOLATILE)?'1':'0';
1043            metadata += ':';
1044            metadata += (arg.ptrAccess & KARG_PTR_RESTRICT)?'1':'0';
1045            metadata += '\n';
1046            argOffset += 16;
1047        }
1048        else if (isKernelArgImage(arg.argType))
1049        {
1050            metadata += ";image:";
1051            metadata += arg.argName.c_str();
1052            metadata += ':';
1053            metadata += imgTypeNamesTable[
1054                    cxuint(arg.argType)-cxuint(KernelArgType::IMAGE)];
1055            metadata += ':';
1056            if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_READ_ONLY)
1057                metadata += "RO";
1058            else if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_WRITE_ONLY)
1059                metadata += "WO";
1060            else if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_READ_WRITE)
1061                metadata += "RW";
1062            else
1063                throw Exception("Invalid image access qualifier!");
1064            metadata += ':';
1065            itocstrCStyle(tempConfig.argResIds[k], numBuf, 21);
1066            metadata += numBuf;
1067            metadata += ":1:";
1068            itocstrCStyle(argOffset, numBuf, 21);
1069            metadata += numBuf;
1070            metadata += '\n';
1071            argOffset += 32;
1072        }
1073        else if (arg.argType == KernelArgType::COUNTER32)
1074        {
1075            metadata += ";counter:";
1076            metadata += arg.argName.c_str();
1077            metadata += ":32:";
1078            itocstrCStyle(tempConfig.argResIds[k], numBuf, 21);
1079            metadata += numBuf;
1080            metadata += ":1:";
1081            itocstrCStyle(argOffset, numBuf, 21);
1082            metadata += numBuf;
1083            metadata += '\n';
1084            argOffset += 16;
1085        }
1086        else
1087        {
1088            metadata += ";value:";
1089            metadata += arg.argName.c_str();
1090            metadata += ':';
1091            const TypeNameVecSize& tp = argTypeNamesTable[cxuint(arg.argType)];
1092            if (tp.kindOfType == KT_UNKNOWN)
1093                throw Exception("Type not supported!");
1094            // type size is aligned (fix for 3 length vectors)
1095            const cxuint typeSize =
1096                cxuint((tp.vecSize==3) ? 4 : tp.vecSize)*std::max(cxbyte(4), tp.elemSize);
1097            metadata += tp.name;
1098            metadata += ':';
1099            itocstrCStyle(tp.vecSize, numBuf, 21);
1100            metadata += numBuf;
1101            metadata += ":1:";
1102            itocstrCStyle(argOffset, numBuf, 21);
1103            metadata += numBuf;
1104            metadata += '\n';
1105            argOffset += (typeSize+15)&~15;
1106        }
1107       
1108        if (arg.ptrAccess & KARG_PTR_CONST)
1109        {
1110            metadata += ";constarg:";
1111            itocstrCStyle(k, numBuf, 21);
1112            metadata += numBuf;
1113            metadata += ':';
1114            metadata += arg.argName.c_str();
1115            metadata += '\n';
1116        }
1117    }
1118   
1119    tempConfig.argsSpace = argOffset;
1120   
1121    if (input->globalData != nullptr)
1122        metadata += ";memory:datareqd\n";
1123    metadata += ";function:1:";
1124    itocstrCStyle(uniqueId, numBuf, 21);
1125    metadata += numBuf;
1126    metadata += '\n';
1127   
1128    for (cxuint sampId = 0; sampId < config.samplers.size(); sampId++)
1129    {   /* constant samplers */
1130        const cxuint samp = config.samplers[sampId];
1131        metadata += ";sampler:unknown_";
1132        itocstrCStyle(samp, numBuf, 21);
1133        metadata += numBuf;
1134        metadata += ':';
1135        itocstrCStyle(sampId+argSamplersNum, numBuf, 21);
1136        metadata += numBuf;
1137        metadata += ":1:";
1138        itocstrCStyle(samp, numBuf, 21);
1139        metadata += numBuf;
1140        metadata += '\n';
1141    }
1142    cxuint sampId = 0;
1143    /* kernel argument samplers */
1144    for (const AmdKernelArgInput& arg: config.args)
1145        if (arg.argType == KernelArgType::SAMPLER)
1146        {
1147            metadata += ";sampler:";
1148            metadata += arg.argName.c_str();
1149            metadata += ':';
1150            itocstrCStyle(sampId, numBuf, 21);
1151            metadata += numBuf;
1152            metadata += ":0:0\n";
1153            sampId++;
1154        }
1155   
1156    if (input->is64Bit)
1157        metadata += ";memory:64bitABI\n";
1158    if (tempConfig.uavId != BINGEN_NOTSUPPLIED)
1159    {
1160        metadata += ";uavid:";
1161        itocstrCStyle(tempConfig.uavId, numBuf, 21);
1162        metadata += numBuf;
1163        metadata += '\n';
1164    }
1165    if (tempConfig.printfId != BINGEN_NOTSUPPLIED)
1166    {
1167        metadata += ";printfid:";
1168        itocstrCStyle(tempConfig.printfId, numBuf, 21);
1169        metadata += numBuf;
1170        metadata += '\n';
1171    }
1172    if (tempConfig.constBufferId != BINGEN_NOTSUPPLIED)
1173    {
1174        metadata += ";cbid:";
1175        itocstrCStyle(tempConfig.constBufferId, numBuf, 21);
1176        metadata += numBuf;
1177        metadata += '\n';
1178    }
1179    if (tempConfig.privateId != BINGEN_NOTSUPPLIED)
1180    {
1181        metadata += ";privateid:";
1182        itocstrCStyle(tempConfig.privateId, numBuf, 21);
1183        metadata += numBuf;
1184        metadata += '\n';
1185    }
1186    for (cxuint k = 0; k < config.args.size(); k++)
1187    {
1188        const AmdKernelArgInput& arg = config.args[k];
1189        metadata += ";reflection:";
1190        itocstrCStyle(k, numBuf, 21);
1191        metadata += numBuf;
1192        metadata += ':';
1193        metadata += arg.typeName.c_str();
1194        metadata += '\n';
1195    }
1196   
1197    metadata += ";ARGEND:__OpenCL_";
1198    metadata += kinput.kernelName.c_str();
1199    metadata += "_kernel\n";
1200   
1201    return metadata;
1202}
1203
1204static void generateCALNotes(FastOutputBuffer& bos, const AmdInput* input,
1205         cxuint driverVersion, const AmdKernelInput& kernel,
1206         const TempAmdKernelConfig& tempConfig)
1207{
1208    const bool isOlderThan1124 = driverVersion < 112402;
1209    const bool isOlderThan1348 = driverVersion < 134805;
1210    const AmdKernelConfig& config = kernel.config;
1211    cxuint readOnlyImages = 0;
1212    cxuint writeOnlyImages = 0;
1213    cxuint samplersNum = config.samplers.size();
1214    cxuint argSamplersNum = 0;
1215    bool isLocalPointers = false;
1216    cxuint constBuffersNum = 2 + (isOlderThan1348 /* cbid:2 for older drivers*/ &&
1217            (input->globalData != nullptr));
1218    cxuint woUsedImagesMask = 0;
1219    for (const AmdKernelArgInput& arg: config.args)
1220    {
1221        if (isKernelArgImage(arg.argType))
1222        {
1223            if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_READ_ONLY)
1224                readOnlyImages++;
1225            if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_WRITE_ONLY)
1226            {
1227                if (arg.used)
1228                    woUsedImagesMask |= (1U<<writeOnlyImages);
1229                writeOnlyImages++;
1230            }
1231        }
1232        else if (arg.argType == KernelArgType::POINTER)
1233        {
1234            if (arg.ptrSpace == KernelPtrSpace::CONSTANT)
1235                constBuffersNum++;
1236            else if (arg.ptrSpace == KernelPtrSpace::LOCAL)
1237                isLocalPointers = true;
1238        }
1239       else if (arg.argType == KernelArgType::SAMPLER)
1240           argSamplersNum++;
1241    }
1242    samplersNum += argSamplersNum;
1243   
1244    // CAL CALNOTE_INPUTS
1245    putCALNoteLE(bos, CALNOTE_ATI_INPUTS, 4*readOnlyImages);
1246    {
1247        uint32_t rdimgIds[128];
1248        for (cxuint k = 0; k < readOnlyImages; k++)
1249            SLEV(rdimgIds[k], isOlderThan1124 ? readOnlyImages-k-1 : k);
1250        bos.writeArray(readOnlyImages, rdimgIds);
1251    }
1252    // CALNOTE_OUTPUTS
1253    putCALNoteLE(bos, CALNOTE_ATI_OUTPUTS, 0);
1254    // CALNOTE_UAV
1255    putCALNoteLE(bos, CALNOTE_ATI_UAV, 16*tempConfig.uavsNum);
1256   
1257    if (isOlderThan1124)
1258    {   // for old drivers
1259        for (cxuint k = 0; k < config.args.size(); k++)
1260        {
1261            const AmdKernelArgInput& arg = config.args[k];
1262            if (isKernelArgImage(arg.argType) &&
1263                (arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_WRITE_ONLY)
1264                /* writeOnlyImages */
1265                putCALUavEntryLE(bos, tempConfig.argResIds[k], 2, imgUavDimTable[
1266                        cxuint(arg.argType)-cxuint(KernelArgType::MIN_IMAGE)], 3);
1267        }
1268        if (config.usePrintf)
1269            putCALUavEntryLE(bos, tempConfig.uavId, 4, 0, 5);
1270        // global buffers
1271        for (cxuint k = 0; k < config.args.size(); k++)
1272        {
1273            const AmdKernelArgInput& arg = config.args[k];
1274            if (arg.argType == KernelArgType::POINTER &&
1275                arg.ptrSpace == KernelPtrSpace::GLOBAL) // uavid
1276                putCALUavEntryLE(bos, tempConfig.argResIds[k], 4, 0, 5);
1277        }
1278    }
1279    else
1280    {   /* in argument order */
1281        for (cxuint k = 0; k < config.args.size(); k++)
1282        {
1283            const AmdKernelArgInput& arg = config.args[k];
1284            if (isKernelArgImage(arg.argType) &&
1285                (arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_WRITE_ONLY)
1286                // write_only images
1287                putCALUavEntryLE(bos, tempConfig.argResIds[k], 2, 2, 5);
1288            else if (arg.argType == KernelArgType::POINTER &&
1289                arg.ptrSpace == KernelPtrSpace::GLOBAL) // uavid
1290                putCALUavEntryLE(bos, tempConfig.argResIds[k], 4, 0, 5);
1291        }
1292       
1293        if (config.usePrintf)
1294            putCALUavEntryLE(bos, tempConfig.uavId, 0, 0, 5);
1295    }
1296   
1297    // CALNOTE_CONDOUT
1298    putCALNoteLE(bos, CALNOTE_ATI_CONDOUT, 4);
1299    bos.writeObject(LEV(uint32_t(config.condOut)));
1300    // CALNOTE_FLOAT32CONSTS
1301    putCALNoteLE(bos, CALNOTE_ATI_FLOAT32CONSTS, 0);
1302    // CALNOTE_INT32CONSTS
1303    putCALNoteLE(bos, CALNOTE_ATI_INT32CONSTS, 0);
1304    // CALNOTE_BOOL32CONSTS
1305    putCALNoteLE(bos, CALNOTE_ATI_BOOL32CONSTS, 0);
1306   
1307    // CALNOTE_EARLYEXIT
1308    putCALNoteLE(bos, CALNOTE_ATI_EARLYEXIT, 4);
1309    bos.writeObject(LEV(uint32_t(config.earlyExit)));
1310   
1311    // CALNOTE_GLOBAL_BUFFERS
1312    putCALNoteLE(bos, CALNOTE_ATI_GLOBAL_BUFFERS, 0);
1313   
1314    // CALNOTE_CONSTANT_BUFFERS
1315    putCALNoteLE(bos, CALNOTE_ATI_CONSTANT_BUFFERS, 8*constBuffersNum);
1316   
1317    if (isOlderThan1124)
1318    {   /* for driver 12.10 */
1319        for (cxuint k = config.args.size(); k > 0; k--)
1320        {
1321            const AmdKernelArgInput& arg = config.args[k-1];
1322            if (arg.argType == KernelArgType::POINTER &&
1323                arg.ptrSpace == KernelPtrSpace::CONSTANT)
1324                putCBMaskLE(bos, tempConfig.argResIds[k-1], arg.constSpaceSize!=0 ?
1325                    ((arg.constSpaceSize+15)>>4) : 4096);
1326        }
1327        if (input->globalData != nullptr)
1328            putCBMaskLE(bos, 2, (input->globalDataSize+15)>>4);
1329        putCBMaskLE(bos, 1, (tempConfig.argsSpace+15)>>4);
1330        putCBMaskLE(bos, 0, 15);
1331    }
1332    else 
1333    {
1334        putCBMaskLE(bos, 0, 0);
1335        putCBMaskLE(bos, 1, 0);
1336        for (cxuint k = 0; k < config.args.size(); k++)
1337        {
1338            const AmdKernelArgInput& arg = config.args[k];
1339            if (arg.argType == KernelArgType::POINTER &&
1340                arg.ptrSpace == KernelPtrSpace::CONSTANT)
1341                putCBMaskLE(bos, tempConfig.argResIds[k], 0);
1342        }
1343        if (isOlderThan1348 && input->globalData != nullptr)
1344            putCBMaskLE(bos, 2, 0);
1345    }
1346   
1347    // CALNOTE_INPUT_SAMPLERS
1348    putCALNoteLE(bos, CALNOTE_ATI_INPUT_SAMPLERS, 8*samplersNum);
1349   
1350    for (cxuint k = 0; k < config.samplers.size(); k++)
1351        putSamplerEntryLE(bos, 0, k+argSamplersNum);
1352    for (cxuint k = 0; k < argSamplersNum; k++)
1353        putSamplerEntryLE(bos, 0, k);
1354   
1355    // CALNOTE_SCRATCH_BUFFERS
1356    putCALNoteLE(bos, CALNOTE_ATI_SCRATCH_BUFFERS, 4);
1357    bos.writeObject<uint32_t>(LEV((config.scratchBufferSize+3)>>2));
1358   
1359    // CALNOTE_PERSISTENT_BUFFERS
1360    putCALNoteLE(bos, CALNOTE_ATI_PERSISTENT_BUFFERS, 0);
1361   
1362    /* PROGRAM_INFO */
1363    size_t userDataElemsNum = config.userDatas.size();
1364    const cxuint progInfoSize = (18+32 +
1365            4*((isOlderThan1124)?16:userDataElemsNum))*8;
1366    putCALNoteLE(bos, CALNOTE_ATI_PROGINFO, progInfoSize);
1367   
1368    putProgInfoEntryLE(bos, 0x80001000U, userDataElemsNum);
1369    cxuint k = 0;
1370    for (k = 0; k < userDataElemsNum; k++)
1371    {
1372        putProgInfoEntryLE(bos, 0x80001001U+(k<<2), config.userDatas[k].dataClass);
1373        putProgInfoEntryLE(bos, 0x80001002U+(k<<2), config.userDatas[k].apiSlot);
1374        putProgInfoEntryLE(bos, 0x80001003U+(k<<2), config.userDatas[k].regStart);
1375        putProgInfoEntryLE(bos, 0x80001004U+(k<<2), config.userDatas[k].regSize);
1376    }
1377    if (isOlderThan1124)
1378        for (k =  userDataElemsNum; k < 16; k++)
1379        {
1380            putProgInfoEntryLE(bos, 0x80001001U+(k<<2), 0);
1381            putProgInfoEntryLE(bos, 0x80001002U+(k<<2), 0);
1382            putProgInfoEntryLE(bos, 0x80001003U+(k<<2), 0);
1383            putProgInfoEntryLE(bos, 0x80001004U+(k<<2), 0);
1384        }
1385   
1386    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
1387    const cxuint ldsShift = arch<GPUArchitecture::GCN1_1 ? 8 : 9;
1388    const uint32_t ldsMask = (1U<<ldsShift)-1U;
1389    const cxuint localSize = (isLocalPointers) ? 32768 : config.hwLocalSize;
1390    uint32_t curPgmRSRC2 = config.pgmRSRC2;
1391    curPgmRSRC2 = curPgmRSRC2 | ((((localSize+ldsMask)>>ldsShift)&0x1ff)<<15);
1392    cxuint pgmUserSGPRsNum = 0;
1393    for (cxuint p = 0; p < userDataElemsNum; p++)
1394        pgmUserSGPRsNum = std::max(pgmUserSGPRsNum,
1395                 config.userDatas[p].regStart+config.userDatas[p].regSize);
1396    pgmUserSGPRsNum = (pgmUserSGPRsNum != 0) ? pgmUserSGPRsNum : 2;
1397    uint32_t dimValues = 0;
1398    if (config.dimMask != BINGEN_DEFAULT)
1399        dimValues = ((config.dimMask&7)<<7) |
1400                (((config.dimMask&4) ? 2 : (config.dimMask&2) ? 1 : 0)<<11);
1401    else // get from current pgmRSRC2
1402        dimValues = (curPgmRSRC2 & 0x1b80U);
1403    curPgmRSRC2 = (curPgmRSRC2 & 0xffffe440U) | ((pgmUserSGPRsNum&0x1f)<<1) |
1404            (config.scratchBufferSize != 0) | dimValues | (config.tgSize ? 0x400 : 0) |
1405            ((uint32_t(config.exceptions)&0x7f)<<24);
1406   
1407    putProgInfoEntryLE(bos, 0x80001041U, config.usedVGPRsNum);
1408    putProgInfoEntryLE(bos, 0x80001042U, config.usedSGPRsNum);
1409    putProgInfoEntryLE(bos, 0x80001863U, getGPUMaxRegistersNum(arch, REGTYPE_SGPR,
1410                           REGCOUNT_NO_VCC));
1411    putProgInfoEntryLE(bos, 0x80001864U, 256);
1412    putProgInfoEntryLE(bos, 0x80001043U, config.floatMode);
1413    putProgInfoEntryLE(bos, 0x80001044U, config.ieeeMode);
1414    putProgInfoEntryLE(bos, 0x80001045U, (config.scratchBufferSize+3)>>2);
1415    putProgInfoEntryLE(bos, 0x00002e13U, curPgmRSRC2);
1416   
1417    if (config.reqdWorkGroupSize[0] != 0 && config.reqdWorkGroupSize[1] != 0 &&
1418        config.reqdWorkGroupSize[2] != 0)
1419    {
1420        putProgInfoEntryLE(bos, 0x8000001cU, config.reqdWorkGroupSize[0]);
1421        putProgInfoEntryLE(bos, 0x8000001dU, config.reqdWorkGroupSize[1]);
1422        putProgInfoEntryLE(bos, 0x8000001eU, config.reqdWorkGroupSize[2]);
1423    }
1424    else
1425    {   /* default */
1426        putProgInfoEntryLE(bos, 0x8000001cU, 256);
1427        putProgInfoEntryLE(bos, 0x8000001dU, 0);
1428        putProgInfoEntryLE(bos, 0x8000001eU, 0);
1429    }
1430    putProgInfoEntryLE(bos, 0x80001841U, 0);
1431    uint32_t uavMask[32];
1432    ::memset(uavMask, 0, 128);
1433    uavMask[0] = woUsedImagesMask;
1434    for (cxuint l = 0; l < config.args.size(); l++)
1435    {
1436        const AmdKernelArgInput& arg = config.args[l];
1437        if (arg.used && arg.argType == KernelArgType::POINTER &&
1438            (arg.ptrSpace == KernelPtrSpace::GLOBAL ||
1439             (arg.ptrSpace == KernelPtrSpace::CONSTANT && !isOlderThan1348)))
1440        {
1441            const cxuint u = tempConfig.argResIds[l];
1442            uavMask[u>>5] |= (1U<<(u&31));
1443        }
1444    }
1445    if (!isOlderThan1348 && config.useConstantData)
1446        uavMask[0] |= 1U<<tempConfig.constBufferId;
1447    if (config.usePrintf) //if printf used
1448    {
1449        if (tempConfig.printfId != BINGEN_NOTSUPPLIED)
1450            uavMask[0] |= 1U<<tempConfig.printfId;
1451        else
1452            uavMask[0] |= 1U<<9;
1453    }
1454   
1455    putProgInfoEntryLE(bos, 0x8000001fU, uavMask[0]);
1456    for (cxuint p = 0; p < 32; p++)
1457        putProgInfoEntryLE(bos, 0x80001843U+p, uavMask[p]);
1458    putProgInfoEntryLE(bos, 0x8000000aU, 1);
1459    putProgInfoEntryLE(bos, 0x80000078U, 64);
1460    putProgInfoEntryLE(bos, 0x80000081U, 32768);
1461    putProgInfoEntryLE(bos, 0x80000082U, ((curPgmRSRC2>>15)&0x1ff)<<8);
1462   
1463    // CAL_SUBCONSTANT_BUFFERS
1464    putCALNoteLE(bos, CALNOTE_ATI_SUB_CONSTANT_BUFFERS, 0);
1465   
1466    // CAL_UAV_MAILBOX_SIZE
1467    putCALNoteLE(bos, CALNOTE_ATI_UAV_MAILBOX_SIZE, 4);
1468    bos.writeObject<uint32_t>(0);
1469   
1470    // CAL_UAV_OP_MASK
1471    putCALNoteLE(bos, CALNOTE_ATI_UAV_OP_MASK, 128);
1472    for (cxuint k = 0; k < 32; k++)
1473        uavMask[k] = LEV(uavMask[k]);
1474    bos.writeArray(32, uavMask);
1475}
1476
1477static std::vector<cxuint> collectUniqueIdsAndFunctionIds(const AmdInput* input)
1478{
1479    std::vector<cxuint> uniqueIds;
1480    for (const AmdKernelInput& kernel: input->kernels)
1481        if (!kernel.useConfig)
1482        {
1483            const char* metadata = kernel.metadata;
1484            if (kernel.metadataSize < 11) // if too short
1485                continue;
1486            size_t pos = 0;
1487            for (pos = 0; pos < kernel.metadataSize-11; pos++)
1488                if (::memcmp(metadata+pos, "\n;uniqueid:", 11) == 0)
1489                    break;
1490            if (pos == kernel.metadataSize-11)
1491                continue; // not found
1492            const char* outEnd;
1493            pos += 11;
1494            try
1495            { uniqueIds.push_back(cstrtovCStyle<cxuint>(metadata+pos,
1496                               metadata+kernel.metadataSize, outEnd)); }
1497            catch(const ParseException& ex)
1498            { } // ignore parse exception
1499            for (; pos < kernel.metadataSize-11; pos++)
1500                if (::memcmp(metadata+pos, "\n;function:", 11) == 0)
1501                    break;
1502            if (pos == kernel.metadataSize-11)
1503                continue; // not found
1504            pos += 11;
1505            const char* funcIdStr = (const char*)::memchr(metadata+pos, ':',
1506                      kernel.metadataSize-pos);
1507            if (funcIdStr == nullptr || funcIdStr+1 == metadata+kernel.metadataSize)
1508                continue;
1509            funcIdStr++;
1510            try
1511            { uniqueIds.push_back(cstrtovCStyle<cxuint>(funcIdStr,
1512                           metadata+kernel.metadataSize, outEnd)); }
1513            catch(const ParseException& ex)
1514            { } // ignore parse exception
1515        }
1516    std::sort(uniqueIds.begin(), uniqueIds.end());
1517    return uniqueIds;
1518}
1519
1520/*
1521 * main routine to generate AmdBin for GPU
1522 * this routine keep original structure of GPU binary (section order, alignment etc)
1523 */
1524
1525void AmdGPUBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
1526             Array<cxbyte>* aPtr) const
1527{
1528    const size_t kernelsNum = input->kernels.size();
1529    CString driverInfo;
1530    uint32_t driverVersion = 99999909U;
1531    if (input->driverInfo.empty())
1532    {
1533        char drvInfoBuf[100];
1534        ::snprintf(drvInfoBuf, 100, "@(#) OpenCL 1.2 AMD-APP (%u.%u).  "
1535                "Driver version: %u.%u (VM)",
1536                 input->driverVersion/100U, input->driverVersion%100U,
1537                 input->driverVersion/100U, input->driverVersion%100U);
1538        driverInfo = drvInfoBuf;
1539        driverVersion = input->driverVersion;
1540    }
1541    else if (input->driverVersion == 0)
1542    {   // parse version
1543        size_t pos = input->driverInfo.find("AMD-APP"); // find AMDAPP
1544        try
1545        {
1546            driverInfo = input->driverInfo;
1547            if (pos != std::string::npos)
1548            {   /* let to parse version number */
1549                pos += 9;
1550                const char* end;
1551                driverVersion = cstrtovCStyle<cxuint>(
1552                        input->driverInfo.c_str()+pos, nullptr, end)*100;
1553                end++;
1554                driverVersion += cstrtovCStyle<cxuint>(end, nullptr, end);
1555            }
1556        }
1557        catch(const ParseException& ex)
1558        { driverVersion = 99999909U; /* newest possible */ }
1559    }
1560   
1561    const bool isOlderThan1124 = driverVersion < 112402;
1562    const bool isOlderThan1348 = driverVersion < 134805;
1563    /* checking input */
1564    if (input->deviceType > GPUDeviceType::GPUDEVICE_MAX)
1565        throw Exception("Unknown GPU device type");
1566   
1567    Array<TempAmdKernelConfig> tempAmdKernelConfigs(kernelsNum);
1568    prepareTempConfigs(driverVersion, input, tempAmdKernelConfigs);
1569   
1570    std::unique_ptr<ElfBinaryGen32> elfBinGen32;
1571    std::unique_ptr<ElfBinaryGen64> elfBinGen64;
1572   
1573    if (gpuDeviceCodeTable[cxuint(input->deviceType)] == 0xffff)
1574        throw Exception("Unsupported GPU device type by OpenCL 1.2 binary format");
1575   
1576    if (input->is64Bit)
1577        elfBinGen64.reset(new ElfBinaryGen64({ 0, 0, ELFOSABI_SYSV, 0, ET_EXEC, 
1578            gpuDeviceCodeTable[cxuint(input->deviceType)], EV_CURRENT, UINT_MAX, 0, 0 }));
1579    else
1580        elfBinGen32.reset(new ElfBinaryGen32({ 0, 0, ELFOSABI_SYSV, 0, ET_EXEC, 
1581            gpuDeviceCodeTable[cxuint(input->deviceType)], EV_CURRENT, UINT_MAX, 0, 0 }));
1582   
1583    Array<TempAmdKernelData> tempAmdKernelDatas(kernelsNum);
1584    cxuint uniqueId = 1024;
1585    std::vector<cxuint> uniqueIds = collectUniqueIdsAndFunctionIds(input);
1586   
1587    uint64_t allInnerBinSize = 0;
1588    size_t rodataSize = 0;
1589    for (size_t i = 0; i < kernelsNum; i++)
1590    {
1591        size_t calNotesSize = 0;
1592        size_t metadataSize = 0;
1593        const AmdKernelInput& kinput = input->kernels[i];
1594        TempAmdKernelData& tempData = tempAmdKernelDatas[i];
1595        tempData.kernelDataGen = KernelDataGen(&kinput);
1596        if (kinput.useConfig)
1597        {   // get new free uniqueId
1598            while (std::binary_search(uniqueIds.begin(), uniqueIds.end(), uniqueId))
1599                uniqueId++;
1600           
1601            const AmdKernelConfig& config = kinput.config;
1602            cxuint readOnlyImages = 0;
1603            cxuint writeOnlyImages = 0;
1604            cxuint uavsNum = 0;
1605            cxuint samplersNum = config.samplers.size();
1606            cxuint argSamplersNum = 0;
1607            cxuint constBuffersNum = 2 + (isOlderThan1348 /* cbid:2 for older drivers*/ &&
1608                    (input->globalData != nullptr));
1609            for (const AmdKernelArgInput& arg: config.args)
1610            {
1611                if (isKernelArgImage(arg.argType))
1612                {
1613                    if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_READ_ONLY)
1614                        readOnlyImages++;
1615                    if ((arg.ptrAccess & KARG_PTR_ACCESS_MASK) == KARG_PTR_WRITE_ONLY)
1616                    {
1617                        uavsNum++;
1618                        writeOnlyImages++;
1619                        if (writeOnlyImages > 8)
1620                            throw Exception("Too many write only images");
1621                    }
1622                }
1623                else if (arg.argType == KernelArgType::POINTER)
1624                {
1625                    if (arg.ptrSpace == KernelPtrSpace::GLOBAL)
1626                        // only global pointers are defined in uav table
1627                        uavsNum++;
1628                    if (arg.ptrSpace == KernelPtrSpace::CONSTANT)
1629                        constBuffersNum++;
1630                }
1631                else if (arg.argType == KernelArgType::SAMPLER)
1632                    argSamplersNum++;
1633            }
1634            samplersNum += argSamplersNum;
1635           
1636            if (config.usePrintf)
1637                uavsNum++;
1638           
1639            TempAmdKernelConfig& tempConfig = tempAmdKernelConfigs[i];
1640            tempConfig.uavsNum = uavsNum;
1641           
1642            tempAmdKernelDatas[i].metadata = generateMetadata(driverVersion, input, kinput,
1643                     tempConfig, argSamplersNum, uniqueId);
1644           
1645            calNotesSize = uint64_t(20*17) /*calNoteHeaders*/ + 16 + 128 + (18+32 +
1646                4*((isOlderThan1124)?16:config.userDatas.size()))*8 /* proginfo */ +
1647                    readOnlyImages*4 /* inputs */ + 16*uavsNum /* uavs */ +
1648                    8*samplersNum /* samplers */ + 8*constBuffersNum /* cbids */;
1649           
1650            metadataSize = tempData.metadata.size() + 32 /* header size */;
1651           
1652            tempData.header[0] = LEV((driverVersion >= 164205)?tempConfig.uavPrivate:0);
1653            tempData.header[1] = 0U;
1654            tempData.header[2] = LEV((isOlderThan1348)? 0 : tempConfig.uavPrivate);
1655            tempData.header[3] = LEV(uint32_t(kinput.config.hwLocalSize));
1656            tempData.header[4] = LEV(uint32_t((input->is64Bit?8:0) |
1657                        (kinput.config.usePrintf?2:0)));
1658            tempData.header[5] = LEV(1U);
1659            tempData.header[6] = 0U;
1660            tempData.header[7] = 0U;
1661           
1662            uniqueId++;
1663        }
1664        else
1665        {
1666            for (const CALNoteInput& calNote: kinput.calNotes)
1667                calNotesSize += uint64_t(20) + calNote.header.descSize;
1668           
1669            metadataSize = kinput.metadataSize + kinput.headerSize;
1670        }
1671       
1672        rodataSize += metadataSize;
1673        /* kernel elf bin generator */
1674        ElfBinaryGen32& kelfBinGen = tempAmdKernelDatas[i].elfBinGen;
1675       
1676        tempAmdKernelDatas[i].calNoteGen = CALNoteGen(input, driverVersion, &kinput,
1677                         &tempAmdKernelConfigs[i]);
1678       
1679        kelfBinGen.setHeader({ 0, 0, 0x64, 1, ET_EXEC, 0x7dU, EV_CURRENT,
1680                    UINT_MAX, 0, 1 });
1681        kelfBinGen.addRegion(ElfRegion32::programHeaderTable());
1682        // CALNoteDir entries
1683        kelfBinGen.addRegion(ElfRegion32(sizeof(CALEncodingEntry),
1684                     (const cxbyte*)&tempAmdKernelDatas[i].calEncEntry, 0));
1685        kelfBinGen.addRegion(ElfRegion32(0, (const cxbyte*)nullptr, 0,
1686                 ".shstrtab", SHT_STRTAB, 0));
1687        kelfBinGen.addRegion(ElfRegion32::sectionHeaderTable());
1688        // CALNotes
1689        kelfBinGen.addRegion(ElfRegion32(calNotesSize,
1690                 &tempAmdKernelDatas[i].calNoteGen, 0));
1691        kelfBinGen.addRegion(ElfRegion32(kinput.codeSize, kinput.code, 0,
1692                 ".text", SHT_PROGBITS, 0));
1693        kelfBinGen.addRegion(ElfRegion32((kinput.data!=nullptr)?kinput.dataSize:4736,
1694                 &tempData.kernelDataGen, 0, ".data",
1695                 SHT_PROGBITS, 0, 0, 0, 0, kinput.dataSize));
1696        kelfBinGen.addRegion(ElfRegion32(0, (const cxbyte*)nullptr, 0,
1697                 ".symtab", SHT_SYMTAB, 0, 0, 1));
1698        if (kinput.extraSymbols.empty()) // default content (2 bytes)
1699            kelfBinGen.addRegion(ElfRegion32(2, (const cxbyte*)"\000\000", 0,
1700                     ".strtab", SHT_STRTAB, 0));
1701        else    // allow to overwirte by elfbingen if some symbol must be put)
1702            kelfBinGen.addRegion(ElfRegion32(0, (const cxbyte*)nullptr, 0,
1703                     ".strtab", SHT_STRTAB, 0));
1704       
1705        /* extra sections */
1706        for (const BinSection& section: kinput.extraSections)
1707            kelfBinGen.addRegion(ElfRegion32(section, kernelBuiltinSectionTable,
1708                         ELFSECTID_STD_MAX, 6));
1709        /* program headers */
1710        kelfBinGen.addProgramHeader({ 0x70000002U, 0, 1, 1, false, 0, 0, 0});
1711        kelfBinGen.addProgramHeader({ PT_NOTE, 0, 4, 1, false, 0, 0, 0 });
1712        kelfBinGen.addProgramHeader({ PT_LOAD, 0, 5, 4, true, 0, 0, 0 });
1713       
1714        /* extra symbols */
1715        for (const BinSymbol& symbol: kinput.extraSymbols)
1716            kelfBinGen.addSymbol(ElfSymbol32(symbol, kernelBuiltinSectionTable,
1717                         ELFSECTID_STD_MAX, 6));
1718       
1719        const uint64_t innerBinSize = kelfBinGen.countSize();
1720        if (innerBinSize > UINT32_MAX)
1721            throw Exception("Inner binary size is too big!");
1722        allInnerBinSize += tempAmdKernelDatas[i].innerBinSize = innerBinSize;
1723       
1724        tempAmdKernelDatas[i].calEncEntry =
1725            { LEV(uint32_t(gpuDeviceInnerCodeTable[cxuint(input->deviceType)])), LEV(4U), 
1726                LEV(0x1c0U), LEV(uint32_t(tempAmdKernelDatas[i].innerBinSize - 0x1c0U)) };
1727    }
1728    if (input->globalData!=nullptr)
1729        rodataSize += input->globalDataSize;
1730   
1731    CL1MainRoDataGen rodataGen(input, tempAmdKernelDatas);
1732    CL1MainTextGen textGen(tempAmdKernelDatas);
1733    CL1MainCommentGen commentGen(input, driverInfo);
1734    CL1MainStrTabGen mainStrTabGen(driverVersion, input);
1735    CL1MainSymTabGen<Elf32Types> mainSymTabGen32(driverVersion, input, tempAmdKernelDatas);
1736    CL1MainSymTabGen<Elf64Types> mainSymTabGen64(driverVersion, input, tempAmdKernelDatas);
1737   
1738    /* main sections and symbols */
1739    if (input->is64Bit)
1740        putMainSections(*elfBinGen64.get(), driverVersion, input, allInnerBinSize, textGen,
1741                    rodataSize, rodataGen, driverInfo, commentGen,
1742                    mainStrTabGen, mainSymTabGen64);
1743    else
1744        putMainSections(*elfBinGen32.get(), driverVersion, input, allInnerBinSize, textGen,
1745                    rodataSize, rodataGen, driverInfo, commentGen,
1746                    mainStrTabGen, mainSymTabGen32);
1747   
1748    const uint64_t binarySize = (input->is64Bit) ? elfBinGen64->countSize() : 
1749            elfBinGen32->countSize();
1750    if (
1751#ifdef HAVE_64BIT
1752        !input->is64Bit &&
1753#endif
1754        binarySize > UINT32_MAX)
1755        throw Exception("Binary size is too big!");
1756    /****
1757     * prepare for write binary to output
1758     ****/
1759    std::unique_ptr<std::ostream> outStreamHolder;
1760    std::ostream* os = nullptr;
1761    if (aPtr != nullptr)
1762    {
1763        aPtr->resize(binarySize);
1764        outStreamHolder.reset(
1765            new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
1766        os = outStreamHolder.get();
1767    }
1768    else if (vPtr != nullptr)
1769    {
1770        vPtr->resize(binarySize);
1771        outStreamHolder.reset(new VectorOStream(*vPtr));
1772        os = outStreamHolder.get();
1773    }
1774    else // from argument
1775        os = osPtr;
1776   
1777    const std::ios::iostate oldExceptions = os->exceptions();
1778    FastOutputBuffer fob(256, *os);
1779    try
1780    {
1781        os->exceptions(std::ios::failbit | std::ios::badbit);
1782        if (input->is64Bit)
1783            elfBinGen64->generate(fob);
1784        else
1785            elfBinGen32->generate(fob);
1786    }
1787    catch(...)
1788    {
1789        os->exceptions(oldExceptions);
1790        throw;
1791    }
1792    os->exceptions(oldExceptions);
1793    assert(fob.getWritten() == binarySize);
1794}
1795
1796
1797void AmdGPUBinGenerator::generate(Array<cxbyte>& array) const
1798{
1799    generateInternal(nullptr, nullptr, &array);
1800}
1801
1802void AmdGPUBinGenerator::generate(std::ostream& os) const
1803{
1804    generateInternal(&os, nullptr, nullptr);
1805}
1806
1807void AmdGPUBinGenerator::generate(std::vector<char>& vector) const
1808{
1809    generateInternal(nullptr, &vector, nullptr);
1810}
1811
1812static const char* amdOclMagicString = "AMD-APP";
1813static std::mutex detectionMutex;
1814static uint64_t detectionFileTimestamp = 0;
1815static std::string detectionAmdOclPath;
1816static uint32_t detectedDriverVersion = 0;
1817
1818static std::string escapePath(const std::string& path)
1819{
1820    std::string newPath;
1821    for (char c: path)
1822        if (c == CLRX_NATIVE_DIR_SEP)
1823            newPath.append("%#");
1824        else if (c == '%')
1825            newPath.append("%%");
1826        else if (c == ':')
1827            newPath.append("%$");
1828        else
1829            newPath += c;
1830    return newPath;
1831}
1832
1833uint32_t CLRX::detectAmdDriverVersion()
1834{
1835    std::lock_guard<std::mutex> lock(detectionMutex);
1836    std::string amdOclPath = findAmdOCL();
1837   
1838    bool notThisSameFile = false;
1839    if (amdOclPath != detectionAmdOclPath)
1840    {
1841        notThisSameFile = true;
1842        detectionAmdOclPath = amdOclPath;
1843    }
1844   
1845    uint64_t timestamp = 0;
1846    try
1847    { timestamp = getFileTimestamp(amdOclPath.c_str()); }
1848    catch(const Exception& ex)
1849    { }
1850   
1851    if (!notThisSameFile && timestamp == detectionFileTimestamp)
1852        return detectedDriverVersion;
1853   
1854    std::string clrxTimestampPath = getHomeDir();
1855    if (!clrxTimestampPath.empty())
1856    {   // first, we check from stored version in config files
1857        clrxTimestampPath = joinPaths(clrxTimestampPath, ".clrxamdocltstamp");
1858        try
1859        { makeDir(clrxTimestampPath.c_str()); }
1860        catch(const std::exception& ex)
1861        { }
1862        // file path
1863        clrxTimestampPath = joinPaths(clrxTimestampPath, escapePath(amdOclPath));
1864        try
1865        {
1866        std::ifstream ifs(clrxTimestampPath.c_str(), std::ios::binary);
1867        if (ifs)
1868        {   // read driver version from stored config files
1869            ifs.exceptions(std::ios::badbit | std::ios::failbit);
1870            uint64_t readedTimestamp = 0;
1871            uint32_t readedVersion = 0;
1872            ifs >> readedTimestamp >> readedVersion;
1873            if (readedTimestamp!=0 && readedVersion!=0 && timestamp==readedTimestamp)
1874            {   // amdocl has not been changed
1875                detectionFileTimestamp = readedTimestamp;
1876                detectedDriverVersion = readedVersion;
1877                return readedVersion;
1878            }
1879        }
1880        }
1881        catch(const std::exception& ex)
1882        { }
1883    }
1884       
1885    detectionFileTimestamp = timestamp;
1886    detectedDriverVersion = 0;
1887    try
1888    {
1889        std::ifstream fs(amdOclPath.c_str(), std::ios::binary);
1890        if (!fs) return 0;
1891        FastInputBuffer fib(256, fs);
1892        size_t index = 0;
1893        while (amdOclMagicString[index]!=0)
1894        {
1895            int c = fib.get();
1896            if (c == std::streambuf::traits_type::eof())
1897                break;
1898            if (amdOclMagicString[index]==c)
1899                index++;
1900            else // reset
1901                index=0;
1902        }
1903        if (amdOclMagicString[index]==0)
1904        { //
1905            char buf[20];
1906            ::memset(buf, 0, 20);
1907            if (fib.get()!=' ')
1908                return 0; // skip space
1909            if (fib.get()!='(')
1910                return 0; // skip '('
1911            // get driver version
1912            fib.read(buf, 20);
1913           
1914            const char* next;
1915            detectedDriverVersion = cstrtoui(buf, buf+20, next)*100;
1916            if (next!=buf+20 && *next=='.') // minor version
1917                detectedDriverVersion += cstrtoui(next+1, buf+20, next)%100;
1918        }
1919       
1920        // write to config
1921        if (!clrxTimestampPath.empty()) // if clrxamdocltstamp set
1922        {   // write to
1923            std::ofstream ofs(clrxTimestampPath.c_str(), std::ios::binary);
1924            ofs << detectionFileTimestamp << " " << detectedDriverVersion;
1925        }
1926    }
1927    catch(const std::exception& ex)
1928    { }
1929    return detectedDriverVersion;
1930}
Note: See TracBrowser for help on using the repository browser.