source: CLRX/CLRadeonExtender/trunk/amdbin/AmdCL2BinGen.cpp @ 2550

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

CLRadeonExtender: Update.

File size: 87.2 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <cstring>
22#include <cstdint>
23#include <cassert>
24#include <bitset>
25#include <fstream>
26#include <algorithm>
27#include <string>
28#include <vector>
29#include <memory>
30#include <CLRX/utils/Containers.h>
31#include <CLRX/utils/InputOutput.h>
32#include <CLRX/amdbin/AmdCL2Binaries.h>
33#include <CLRX/amdbin/AmdCL2BinGen.h>
34
35using namespace CLRX;
36
37static const cxuint innerBinSectonTableLen = AMDCL2SECTID_MAX+1-ELFSECTID_START;
38
39void AmdCL2Input::addEmptyKernel(const char* kernelName)
40{
41    AmdCL2KernelInput kernel{};
42    kernel.kernelName = kernelName;
43   
44    kernel.config.usedSGPRsNum = kernel.config.usedVGPRsNum = BINGEN_DEFAULT;
45    kernel.config.floatMode = 0xc0;
46    kernel.config.dimMask = BINGEN_DEFAULT;
47    kernels.push_back(std::move(kernel));
48}
49
50AmdCL2GPUBinGenerator::AmdCL2GPUBinGenerator() : manageable(false), input(nullptr)
51{ }
52
53AmdCL2GPUBinGenerator::AmdCL2GPUBinGenerator(const AmdCL2Input* amdInput)
54        : manageable(false), input(amdInput)
55{ }
56
57AmdCL2GPUBinGenerator::AmdCL2GPUBinGenerator(GPUDeviceType deviceType,
58       uint32_t archMinor, uint32_t archStepping,
59       uint32_t driverVersion, size_t globalDataSize, const cxbyte* globalData,
60       size_t rwDataSize, const cxbyte* rwData, 
61       const std::vector<AmdCL2KernelInput>& kernelInputs)
62        : manageable(true), input(nullptr)
63{
64    input = new AmdCL2Input{deviceType, archMinor, archStepping,
65                globalDataSize, globalData, rwDataSize, rwData, 0, 0, 0,
66                nullptr, false, { }, { }, driverVersion, "", "", kernelInputs };
67}
68
69AmdCL2GPUBinGenerator::AmdCL2GPUBinGenerator(GPUDeviceType deviceType,
70       uint32_t archMinor, uint32_t archStepping,
71       uint32_t driverVersion, size_t globalDataSize, const cxbyte* globalData,
72       size_t rwDataSize, const cxbyte* rwData,
73       std::vector<AmdCL2KernelInput>&& kernelInputs)
74        : manageable(true), input(nullptr)
75{
76    input = new AmdCL2Input{deviceType, archMinor, archStepping,
77                globalDataSize, globalData, rwDataSize, rwData, 0, 0, 0,
78                nullptr, false, { }, { }, driverVersion, "", "",
79                std::move(kernelInputs) };
80}
81
82AmdCL2GPUBinGenerator::~AmdCL2GPUBinGenerator()
83{
84    if (manageable)
85        delete input;
86}
87
88void AmdCL2GPUBinGenerator::setInput(const AmdCL2Input* input)
89{
90    if (manageable)
91        delete input;
92    manageable = false;
93    this->input = input;
94}
95
96struct CLRX_INTERNAL TempAmdCL2KernelData
97{
98    size_t metadataSize;
99    size_t isaMetadataSize;
100    size_t stubSize;
101    size_t setupSize;
102    size_t codeSize;
103    bool useLocals;
104    uint32_t pipesUsed;
105    Array<uint16_t> argResIds;
106};
107
108struct CLRX_INTERNAL ArgTypeSizes
109{
110    cxbyte type;
111    cxbyte elemSize;
112    cxbyte vectorSize;
113};
114
115static const ArgTypeSizes argTypeSizesTable[] =
116{
117    { 6, 1, 1 /*void */ },
118    { 6, 1, 1 /*uchar*/ }, { 6, 1, 1, /*char*/ },
119    { 7, 2, 1, /*ushort*/ }, { 7, 2, 1, /*short*/ },
120    { 8, 4, 1, /*uint*/ }, { 8, 4, 1, /*INT*/ },
121    { 9, 8, 1, /*ulong*/ }, { 9, 8, 1, /*long*/ },
122    { 11, 4, 1, /*float*/ }, { 12, 8, 1, /*double*/ },
123    { 7, 8, 1, /*pointer*/ },
124    { 0, 32, 1, /*image*/ }, { 0, 32, 1, /*image1d*/ }, { 0, 32, 1, /*image1da */ },
125    { 0, 32, 1, /*image1db*/ }, { 0, 32, 1, /*image2d*/ }, { 0, 32, 1, /*image2da*/ },
126    { 0, 32, 1, /*image3d*/ },
127    { 6, 1, 2, /*uchar2*/ }, { 6, 1, 3, /*uchar3*/ }, { 6, 1, 4, /*uchar4*/ },
128    { 6, 1, 8, /*uchar8*/ }, { 6, 1, 16, /*uchar16*/ },
129    { 6, 1, 2, /*char2*/ }, { 6, 1, 3, /*char3*/ }, { 6, 1, 4, /*char4*/ },
130    { 6, 1, 8, /*char8*/ }, { 6, 1, 16, /*char16*/ },
131    { 7, 2, 2, /*ushort2*/ }, { 7, 2, 3, /*ushort3*/ }, { 7, 2, 4, /*ushort4*/ },
132    { 7, 2, 8, /*ushort8*/ }, { 7, 2, 16, /*ushort16*/ },
133    { 7, 2, 2, /*short2*/ }, { 7, 2, 3, /*short3*/ }, { 7, 2, 4, /*short4*/ },
134    { 7, 2, 8, /*short8*/ }, { 7, 2, 16, /*short16*/ },
135    { 8, 4, 2, /*uint2*/ }, { 8, 4, 3, /*uint3*/ }, { 8, 4, 4, /*uint4*/ },
136    { 8, 4, 8, /*uint8*/ }, { 8, 4, 16, /*uint16*/ },
137    { 8, 4, 2, /*int2*/ }, { 8, 4, 3, /*int3*/ }, { 8, 4, 4, /*int4*/ },
138    { 8, 4, 8, /*int8*/ }, { 8, 4, 16, /*int16*/ },
139    { 9, 8, 2, /*ulong2*/ }, { 9, 8, 3, /*ulong3*/ }, { 9, 8, 4, /*ulong4*/ },
140    { 9, 8, 8, /*ulong8*/ }, { 9, 8, 16, /*ulong16*/ },
141    { 9, 8, 2, /*long2*/ }, { 9, 8, 3, /*long3*/ }, { 9, 8, 4, /*long4*/ },
142    { 9, 8, 8, /*long8*/ }, { 9, 8, 16, /*long16*/ },
143    { 11, 4, 2, /*float2*/ }, { 11, 4, 3, /*float3*/ }, { 11, 4, 4, /*float4*/ },
144    { 11, 4, 8, /*float8*/ }, { 11, 4, 16, /*float16*/ },
145    { 12, 8, 2, /*double2*/ }, { 12, 8, 3, /*double3*/ }, { 12, 8, 4, /*double4*/ },
146    { 12, 8, 8, /*double8*/ }, { 12, 8, 16, /*double16*/ },
147    { 0, 16, 1, /* sampler*/ }, { 15, 0, 0, /*structure*/ }, { 0, 0, 0, /*counter*/ },
148    { 0, 0, 0, /*counter64*/ }, { 7, 16, 1, /* pipe*/ }, { 18, 16, 1, /*cmdqueue*/ },
149    { 7, 8, 1, /*clkevent*/ }
150};
151
152static const uint32_t gpuDeviceCodeTable[21] =
153{
154    UINT_MAX, // GPUDeviceType::CAPE_VERDE
155    UINT_MAX, // GPUDeviceType::PITCAIRN
156    UINT_MAX, // GPUDeviceType::TAHITI
157    UINT_MAX, // GPUDeviceType::OLAND
158    6, // GPUDeviceType::BONAIRE
159    1, // GPUDeviceType::SPECTRE
160    2, // GPUDeviceType::SPOOKY
161    3, // GPUDeviceType::KALINDI
162    UINT_MAX, // GPUDeviceType::HAINAN
163    7, // GPUDeviceType::HAWAII
164    8, // GPUDeviceType::ICELAND
165    9, // GPUDeviceType::TONGA
166    4, // GPUDeviceType::MULLINS
167    17, // GPUDeviceType::FIJI
168    16, // GPUDeviceType::CARRIZO
169    15, // GPUDeviceType::DUMMY
170    UINT_MAX, // GPUDeviceType::GOOSE
171    UINT_MAX, // GPUDeviceType::HORSE
172    UINT_MAX, // GPUDeviceType::STONEY
173    UINT_MAX, // GPUDeviceType::ELLESMERE
174    UINT_MAX  // GPUDeviceType::BAFFIN
175};
176
177static const uint32_t gpuDeviceCodeTable15_7[21] =
178{
179    UINT_MAX, // GPUDeviceType::CAPE_VERDE
180    UINT_MAX, // GPUDeviceType::PITCAIRN
181    UINT_MAX, // GPUDeviceType::TAHITI
182    UINT_MAX, // GPUDeviceType::OLAND
183    6, // GPUDeviceType::BONAIRE
184    1, // GPUDeviceType::SPECTRE
185    2, // GPUDeviceType::SPOOKY
186    3, // GPUDeviceType::KALINDI
187    UINT_MAX, // GPUDeviceType::HAINAN
188    7, // GPUDeviceType::HAWAII
189    8, // GPUDeviceType::ICELAND
190    9, // GPUDeviceType::TONGA
191    4, // GPUDeviceType::MULLINS
192    16, // GPUDeviceType::FIJI
193    15, // GPUDeviceType::CARRIZO
194    UINT_MAX, // GPUDeviceType::DUMMY
195    UINT_MAX, // GPUDeviceType::GOOSE
196    UINT_MAX, // GPUDeviceType::HORSE
197    UINT_MAX, // GPUDeviceType::STONEY
198    UINT_MAX, // GPUDeviceType::ELLESMERE
199    UINT_MAX  // GPUDeviceType::BAFFIN
200};
201
202static const uint32_t gpuDeviceCodeTable16_3[21] =
203{
204    UINT_MAX, // GPUDeviceType::CAPE_VERDE
205    UINT_MAX, // GPUDeviceType::PITCAIRN
206    UINT_MAX, // GPUDeviceType::TAHITI
207    UINT_MAX, // GPUDeviceType::OLAND
208    6, // GPUDeviceType::BONAIRE
209    1, // GPUDeviceType::SPECTRE
210    2, // GPUDeviceType::SPOOKY
211    3, // GPUDeviceType::KALINDI
212    UINT_MAX, // GPUDeviceType::HAINAN
213    7, // GPUDeviceType::HAWAII
214    8, // GPUDeviceType::ICELAND
215    9, // GPUDeviceType::TONGA
216    4, // GPUDeviceType::MULLINS
217    16, // GPUDeviceType::FIJI
218    15, // GPUDeviceType::CARRIZO
219    UINT_MAX, // GPUDeviceType::DUMMY
220    13, // GPUDeviceType::GOOSE
221    12, // GPUDeviceType::HORSE
222    17, // GPUDeviceType::STONEY
223    UINT_MAX, // GPUDeviceType::ELLESMERE
224    UINT_MAX  // GPUDeviceType::BAFFIN
225};
226
227static const uint32_t gpuDeviceCodeTableGPUPRO[21] =
228{
229    UINT_MAX, // GPUDeviceType::CAPE_VERDE
230    UINT_MAX, // GPUDeviceType::PITCAIRN
231    UINT_MAX, // GPUDeviceType::TAHITI
232    UINT_MAX, // GPUDeviceType::OLAND
233    6, // GPUDeviceType::BONAIRE
234    1, // GPUDeviceType::SPECTRE
235    2, // GPUDeviceType::SPOOKY
236    3, // GPUDeviceType::KALINDI
237    UINT_MAX, // GPUDeviceType::HAINAN
238    7, // GPUDeviceType::HAWAII
239    8, // GPUDeviceType::ICELAND
240    9, // GPUDeviceType::TONGA
241    4, // GPUDeviceType::MULLINS
242    14, // GPUDeviceType::FIJI
243    13, // GPUDeviceType::CARRIZO
244    UINT_MAX, // GPUDeviceType::DUMMY
245    UINT_MAX, // GPUDeviceType::GOOSE
246    UINT_MAX, // GPUDeviceType::HORSE
247    15, // GPUDeviceType::STONEY
248    17, // GPUDeviceType::ELLESMERE
249    16 // GPUDeviceType::BAFFIN
250};
251
252static const uint16_t mainBuiltinSectionTable[] =
253{
254    1, // ELFSECTID_SHSTRTAB
255    2, // ELFSECTID_STRTAB
256    3, // ELFSECTID_SYMTAB
257    SHN_UNDEF, // ELFSECTID_DYNSTR
258    SHN_UNDEF, // ELFSECTID_DYNSYM
259    6, // ELFSECTID_TEXT
260    5, // ELFSECTID_RODATA
261    SHN_UNDEF, // ELFSECTID_DATA
262    SHN_UNDEF, // ELFSECTID_BSS
263    4 // ELFSECTID_COMMENT
264};
265
266static const cxbyte kernelIsaMetadata[] =
267{
268    0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00,
269    0x00, 0x00, 0x00, 0x08, 0x42, 0x09, 0x00, 0x00,
270    0x00, 0x00, 0x00, 0x00
271};
272
273static void prepareKernelTempData(const AmdCL2Input* input,
274          Array<TempAmdCL2KernelData>& tempDatas)
275{
276    const bool newBinaries = input->driverVersion >= 191205;
277    const bool is16_3Ver = input->driverVersion >= 200406;
278    const size_t kernelsNum = input->kernels.size();
279   
280    const size_t samplersNum = (input->samplerConfig) ?
281                input->samplers.size() : (input->samplerInitSize>>3);
282   
283    for (size_t i = 0; i < kernelsNum; i++)
284    {
285        const AmdCL2KernelInput& kernel = input->kernels[i];
286        TempAmdCL2KernelData& tempData = tempDatas[i];
287        if (newBinaries && (kernel.isaMetadataSize!=0 || kernel.isaMetadata!=nullptr))
288            throw Exception("ISA metadata allowed for old driver binaries");
289        if (newBinaries && (kernel.stubSize!=0 || kernel.stub!=nullptr))
290            throw Exception("Kernel stub allowed for old driver binaries");
291        /* check relocations */
292        if (newBinaries)
293            for (const AmdCL2RelInput& rel: kernel.relocations)
294            {
295                if (rel.type > RELTYPE_HIGH_32BIT || rel.symbol > 2)
296                    throw Exception("Wrong relocation symbol or type");
297                if (rel.offset+4 > kernel.codeSize)
298                    throw Exception("Relocation offset outside code size");
299            }
300       
301        if (!kernel.useConfig)
302        {   // if no kernel configuration
303            tempData.metadataSize = kernel.metadataSize;
304            tempData.isaMetadataSize = (kernel.isaMetadata!=nullptr) ?
305                        kernel.isaMetadataSize : sizeof(kernelIsaMetadata);
306            tempData.setupSize = kernel.setupSize;
307            tempData.stubSize = kernel.stubSize;
308        }
309        else
310        {   // if kernel configuration present
311            const cxuint argsNum = kernel.config.args.size();
312            size_t out = ((newBinaries) ? ((is16_3Ver) ? 303 : 254) : 246) +
313                        (argsNum + 1)*88;
314            for (const AmdKernelArgInput& arg: kernel.config.args)
315                    out += arg.argName.size() + arg.typeName.size() + 2;
316            out += 48;
317           
318            /// if kernels uses locals
319            tempData.pipesUsed = 0;
320            tempData.useLocals = (kernel.config.localSize != 0);
321            if (!tempData.useLocals)
322                for (const AmdKernelArgInput& inarg: kernel.config.args)
323                    if (inarg.argType == KernelArgType::POINTER &&
324                                inarg.ptrSpace == KernelPtrSpace::LOCAL)
325                    {
326                        tempData.useLocals = true;
327                        break;
328                    }
329            for (const AmdKernelArgInput& inarg: kernel.config.args)
330                if (inarg.argType == KernelArgType::PIPE && inarg.used)
331                    tempData.pipesUsed++;
332           
333            std::bitset<128> imgRoMask;
334            std::bitset<64> imgWoMask;
335            std::bitset<64> imgRWMask;
336            std::bitset<16> samplerMask;
337            tempData.argResIds.resize(argsNum);
338            // collect set bit to masks
339            for (cxuint k = 0; k < argsNum; k++)
340            {
341                const AmdKernelArgInput& inarg = kernel.config.args[k];
342                if (inarg.resId != BINGEN_DEFAULT)
343                {
344                    if (inarg.argType == KernelArgType::SAMPLER)
345                    {
346                        if (inarg.resId >= 16)
347                            throw Exception("SamplerId out of range!");
348                        if (samplerMask[inarg.resId])
349                            throw Exception("SamplerId already used!");
350                        samplerMask.set(inarg.resId);
351                        tempData.argResIds[k] = inarg.resId;
352                    }
353                    else if (isKernelArgImage(inarg.argType))
354                    {
355                        uint32_t imgAccess = inarg.ptrAccess & KARG_PTR_ACCESS_MASK;
356                        if (imgAccess == KARG_PTR_READ_ONLY)
357                        {
358                            if (inarg.resId >= 128)
359                                throw Exception("RdOnlyImgId out of range!");
360                            if (imgRoMask[inarg.resId])
361                                throw Exception("RdOnlyImgId already used!");
362                            imgRoMask.set(inarg.resId);
363                            tempData.argResIds[k] = inarg.resId;
364                        }
365                        else if (imgAccess == KARG_PTR_WRITE_ONLY)
366                        {
367                            if (inarg.resId >= 64)
368                                throw Exception("WrOnlyImgId out of range!");
369                            if (imgWoMask[inarg.resId])
370                                throw Exception("WrOnlyImgId already used!");
371                            imgWoMask.set(inarg.resId);
372                            tempData.argResIds[k] = inarg.resId;
373                        }
374                        else // read-write images
375                        {
376                            if (inarg.resId >= 64)
377                                throw Exception("RdWrImgId out of range!");
378                            if (imgRWMask[inarg.resId])
379                                throw Exception("RdWrImgId already used!");
380                            imgRWMask.set(inarg.resId);
381                            tempData.argResIds[k] = inarg.resId;
382                        }
383                    }
384                }
385            }
386           
387            cxuint imgRoCount = 0;
388            cxuint imgWoCount = 0;
389            cxuint imgRWCount = 0;
390            cxuint samplerCount = 0;
391            // now, we can set resId for argument that have no resid
392            for (cxuint k = 0; k < argsNum; k++)
393            {
394                const AmdKernelArgInput& inarg = kernel.config.args[k];
395                if (inarg.resId == BINGEN_DEFAULT)
396                {
397                    if (inarg.argType == KernelArgType::SAMPLER)
398                    {
399                        for (; samplerCount < 16 && samplerMask[samplerCount];
400                             samplerCount++);
401                        if (samplerCount == 16)
402                            throw Exception("SamplerId out of range!");
403                        tempData.argResIds[k] = samplerCount++;
404                    }
405                    else if (isKernelArgImage(inarg.argType))
406                    {
407                        uint32_t imgAccess = inarg.ptrAccess & KARG_PTR_ACCESS_MASK;
408                        if (imgAccess == KARG_PTR_READ_ONLY)
409                        {
410                            for (; imgRoCount < 128 && imgRoMask[imgRoCount]; imgRoCount++);
411                            if (imgRoCount == 128)
412                                throw Exception("RdOnlyImgId out of range!");
413                            tempData.argResIds[k] = imgRoCount++;
414                        }
415                        else if (imgAccess == KARG_PTR_WRITE_ONLY)
416                        {
417                            for (; imgWoCount < 64 && imgWoMask[imgWoCount]; imgWoCount++);
418                            if (imgWoCount == 64)
419                                throw Exception("WrOnlyImgId out of range!");
420                            tempData.argResIds[k] = imgWoCount++;
421                        }
422                        else // read-write images
423                        {
424                            for (; imgRWCount < 64 && imgRWMask[imgRWCount]; imgRWCount++);
425                            if (imgRWCount == 128)
426                                throw Exception("RdWrImgId out of range!");
427                            tempData.argResIds[k] = imgRWCount++;
428                        }
429                    }
430                }
431            }
432           
433            // check sampler list
434            for (cxuint sampler: kernel.config.samplers)
435                if (sampler >= samplersNum)
436                    throw Exception("SamplerId out of range");
437           
438            tempData.metadataSize = out;
439            tempData.setupSize = 256;
440            tempData.stubSize = tempData.isaMetadataSize = 0;
441            if (!newBinaries)
442            {
443                tempData.stubSize = 0xa60;
444                tempData.isaMetadataSize = sizeof(kernelIsaMetadata);
445            }
446        }
447        tempData.codeSize = kernel.codeSize;
448    }
449}
450
451// fast and memory efficient String table generator for main binary
452class CLRX_INTERNAL CL2MainStrTabGen: public ElfRegionContent
453{
454private:
455    const AmdCL2Input* input;
456    bool withBrig;
457public:
458    explicit CL2MainStrTabGen(const AmdCL2Input* _input) : input(_input), withBrig(false)
459    {
460        for (const BinSection& section: input->extraSections)
461            if (section.name==".brig")
462            {
463                withBrig = true;
464                break;
465            }
466    }
467   
468    size_t size() const
469    {
470        const bool newBinaries = input->driverVersion >= 191205;
471        size_t size = 1;
472        if (!input->compileOptions.empty())
473            size += 26;
474        if (withBrig)
475            size += 9; // __BRIG__
476        //size +=
477        if (newBinaries)
478            for (const AmdCL2KernelInput& kernel: input->kernels)
479                size += kernel.kernelName.size() + 19 + 17;
480        else // old binaries
481            for (const AmdCL2KernelInput& kernel: input->kernels)
482                size += kernel.kernelName.size()*3 + 19 + 17 + 16*2 + 17 + 15;
483        size += 19; // acl version string
484        /// extra symbols
485        for (const BinSymbol& symbol: input->extraSymbols)
486            size += symbol.name.size()+1;
487        return size;
488    }
489   
490    void operator()(FastOutputBuffer& fob) const
491    {
492        const bool newBinaries = input->driverVersion >= 191205;
493        fob.put(0);
494        if (!input->compileOptions.empty())
495            fob.write(26, "__OpenCL_compiler_options");
496       
497        for (const AmdCL2KernelInput& kernel: input->kernels)
498        {   // put kernel metadata symbol names
499            fob.write(19, "__OpenCL_&__OpenCL_");
500            fob.write(kernel.kernelName.size(), kernel.kernelName.c_str());
501            fob.write(17, "_kernel_metadata");
502        }
503        if (withBrig)
504            fob.write(9, "__BRIG__");
505        if (!newBinaries)
506            for (const AmdCL2KernelInput& kernel: input->kernels)
507            {   // put kernel ISA/binary symbol names
508                fob.write(16, "__ISA_&__OpenCL_");
509                fob.write(kernel.kernelName.size(), kernel.kernelName.c_str());
510                fob.write(31, "_kernel_binary\000__ISA_&__OpenCL_");
511                fob.write(kernel.kernelName.size(), kernel.kernelName.c_str());
512                fob.write(17, "_kernel_metadata");
513            }
514        fob.write(19, "acl_version_string");
515        /// extra symbols
516        for (const BinSymbol& symbol: input->extraSymbols)
517            fob.write(symbol.name.size()+1, symbol.name.c_str());
518    }
519};
520
521// fast and memory efficient symbol table generator for main binary
522class CLRX_INTERNAL CL2MainSymTabGen: public ElfRegionContent
523{
524private:
525    const AmdCL2Input* input;
526    bool withBrig;
527    uint16_t brigIndex;
528    const Array<TempAmdCL2KernelData>& tempDatas;
529    const CString& aclVersion;
530    cxuint extraSectionIndex;
531public:
532    CL2MainSymTabGen(const AmdCL2Input* _input,
533             const Array<TempAmdCL2KernelData>& _tempDatas,
534             const CString& _aclVersion, cxuint _extraSectionIndex)
535             : input(_input), withBrig(false), tempDatas(_tempDatas),
536               aclVersion(_aclVersion), extraSectionIndex(_extraSectionIndex)
537    {
538        for (brigIndex = 0; brigIndex < input->extraSections.size(); brigIndex++)
539        {
540            const BinSection& section = input->extraSections[brigIndex];
541            if (section.name==".brig")
542            {
543                withBrig = true;
544                break;
545            }
546        }
547    }
548   
549    size_t size() const
550    {
551        const bool newBinaries = input->driverVersion >= 191205;
552        return sizeof(Elf64_Sym)*(1 + (!input->compileOptions.empty()) +
553            input->kernels.size()*(newBinaries ? 1 : 3) +
554            (withBrig) + 1 /* acl_version */ + input->extraSymbols.size());
555    }
556   
557    void operator()(FastOutputBuffer& fob) const
558    {
559        const bool newBinaries = input->driverVersion >= 191205;
560        fob.fill(sizeof(Elf64_Sym), 0);
561        Elf64_Sym sym;
562        size_t nameOffset = 1;
563        if (!input->compileOptions.empty())
564        {
565            SLEV(sym.st_name, nameOffset);
566            SLEV(sym.st_shndx, 4);
567            SLEV(sym.st_value, 0);
568            SLEV(sym.st_size, input->compileOptions.size());
569            sym.st_info = ELF64_ST_INFO(STB_LOCAL, STT_OBJECT);
570            sym.st_other = 0;
571            nameOffset += 26;
572            fob.writeObject(sym);
573        }
574        size_t rodataPos = 0;
575        size_t textPos = 0;
576        for (size_t i = 0; i < input->kernels.size(); i++)
577        {
578            const AmdCL2KernelInput& kernel = input->kernels[i];
579            const TempAmdCL2KernelData& tempData = tempDatas[i];
580            SLEV(sym.st_name, nameOffset);
581            SLEV(sym.st_shndx, 5);
582            SLEV(sym.st_value, rodataPos);
583            SLEV(sym.st_size, tempData.metadataSize);
584            sym.st_info = ELF64_ST_INFO(STB_LOCAL, STT_OBJECT);
585            sym.st_other = 0;
586            nameOffset += kernel.kernelName.size() + 19 + 17;
587            rodataPos += tempData.metadataSize;
588            fob.writeObject(sym);
589        }
590        if (withBrig)
591        {   // put __BRIG__ symbol
592            SLEV(sym.st_name, nameOffset);
593            SLEV(sym.st_shndx, 7 + brigIndex);
594            SLEV(sym.st_value, 0);
595            SLEV(sym.st_size, input->extraSections[brigIndex].size);
596            sym.st_info = ELF64_ST_INFO(STB_LOCAL, STT_OBJECT);
597            sym.st_other = 0;
598            nameOffset += 9;
599            fob.writeObject(sym);
600        }
601       
602        if (!newBinaries)
603        { // put binary and ISA metadata symbols
604            for (size_t i = 0; i < input->kernels.size(); i++)
605            {
606                const AmdCL2KernelInput& kernel = input->kernels[i];
607                const TempAmdCL2KernelData& tempData = tempDatas[i];
608                // put kernel binary symbol
609                SLEV(sym.st_name, nameOffset);
610                SLEV(sym.st_shndx, 6);
611                SLEV(sym.st_value, textPos);
612                SLEV(sym.st_size, tempData.stubSize+tempData.setupSize+tempData.codeSize);
613                sym.st_info = ELF64_ST_INFO(STB_LOCAL, STT_FUNC);
614                sym.st_other = 0;
615                nameOffset += 16 + kernel.kernelName.size() + 15;
616                textPos += tempData.stubSize+tempData.setupSize+tempData.codeSize;
617                fob.writeObject(sym);
618                // put ISA metadata symbol
619                SLEV(sym.st_name, nameOffset);
620                SLEV(sym.st_shndx, 5);
621                SLEV(sym.st_value, rodataPos);
622                SLEV(sym.st_size, tempData.isaMetadataSize);
623                sym.st_info = ELF64_ST_INFO(STB_LOCAL, STT_OBJECT);
624                sym.st_other = 0;
625                nameOffset += 16 + kernel.kernelName.size() + 17;
626                rodataPos += tempData.isaMetadataSize;
627                fob.writeObject(sym);
628            }
629        }
630        // acl_version_string
631        SLEV(sym.st_name, nameOffset);
632        SLEV(sym.st_shndx, 4);
633        SLEV(sym.st_value, input->compileOptions.size());
634        SLEV(sym.st_size, aclVersion.size());
635        sym.st_info = ELF64_ST_INFO(STB_LOCAL, STT_OBJECT);
636        sym.st_other = 0;
637        fob.writeObject(sym);
638        nameOffset += 19;
639       
640        for (const BinSymbol& symbol: input->extraSymbols)
641        {
642            SLEV(sym.st_name, nameOffset);
643            SLEV(sym.st_shndx, convertSectionId(symbol.sectionId, mainBuiltinSectionTable,
644                            ELFSECTID_STD_MAX, extraSectionIndex));
645            SLEV(sym.st_size, symbol.size);
646            SLEV(sym.st_value, symbol.value);
647            sym.st_info = symbol.info;
648            sym.st_other = symbol.other;
649            nameOffset += symbol.name.size()+1;
650            fob.writeObject(sym);
651        }
652    }
653};
654
655class CLRX_INTERNAL CL2MainCommentGen: public ElfRegionContent
656{
657private:
658    const AmdCL2Input* input;
659    const CString& aclVersion;
660public:
661    explicit CL2MainCommentGen(const AmdCL2Input* _input, const CString& _aclVersion) :
662            input(_input), aclVersion(_aclVersion)
663    { }
664   
665    void operator()(FastOutputBuffer& fob) const
666    {
667        fob.write(input->compileOptions.size(), input->compileOptions.c_str());
668        fob.write(aclVersion.size(), aclVersion.c_str());
669    }
670};
671
672struct CLRX_INTERNAL TypeNameVecSize
673{
674    cxbyte elemSize;
675    cxbyte vecSize;
676};
677
678static const uint32_t ptrSpacesTable[4] = { 0, 3, 5, 4 };
679
680class CLRX_INTERNAL CL2MainRodataGen: public ElfRegionContent
681{
682private:
683    const AmdCL2Input* input;
684    const Array<TempAmdCL2KernelData>& tempDatas;
685public:
686    explicit CL2MainRodataGen(const AmdCL2Input* _input,
687              const Array<TempAmdCL2KernelData>& _tempDatas) : input(_input),
688              tempDatas(_tempDatas)
689    { }
690   
691    size_t size() const
692    {
693        const bool newBinaries = input->driverVersion >= 191205;
694        size_t out = 0;
695        for (const TempAmdCL2KernelData& tempData: tempDatas)
696            out += tempData.metadataSize;
697           
698        if (!newBinaries)
699            for (const TempAmdCL2KernelData& tempData: tempDatas)
700                out += tempData.isaMetadataSize;
701        return out;
702    }
703   
704    void writeMetadata(cxuint kernelId, const TempAmdCL2KernelData& tempData,
705               const AmdCL2KernelConfig& config, FastOutputBuffer& fob) const
706    {
707        const bool newBinaries = input->driverVersion >= 191205;
708        const bool is16_3Ver = input->driverVersion >= 200406;
709        AmdCL2GPUMetadataHeader header;
710        cxuint argsNum = config.args.size();
711       
712        SLEV(header.size, (newBinaries) ? (is16_3Ver ? 0x110 : 0xe0) : 0xd8);
713        SLEV(header.metadataSize, tempData.metadataSize);
714        SLEV(header.unknown1[0], 0x3);
715        SLEV(header.unknown1[1], 0x1);
716        SLEV(header.unknown1[2], 0x68);
717        uint32_t options = config.reqdWorkGroupSize[0]!=0 ? 0x24 : 0x20;
718        if (((config.useEnqueue || config.localSize!=0 || tempData.pipesUsed!=0 ||
719                config.scratchBufferSize!=0) && !newBinaries))
720            options |= 0x100U;
721        SLEV(header.options, options);
722        SLEV(header.kernelId, kernelId+1024);
723        header.unknownx = 0;
724        header.unknowny = 0;
725        SLEV(header.unknown2[0], 0x0100000008ULL);
726        SLEV(header.unknown2[1], 0x0200000001ULL);
727        SLEV(header.reqdWorkGroupSize[0], config.reqdWorkGroupSize[0]);
728        SLEV(header.reqdWorkGroupSize[1], config.reqdWorkGroupSize[1]);
729        SLEV(header.reqdWorkGroupSize[2], config.reqdWorkGroupSize[2]);
730        header.unknown3[0] = 0;
731        header.unknown3[1] = 0;
732        SLEV(header.firstNameLength, 0x15);
733        SLEV(header.secondNameLength, 0x7);
734        for (cxuint i = 0; i < 3; i++)
735            header.unknown4[i] = 0;
736        if (!newBinaries)
737            SLEV(header.pipesUsage, (config.scratchBufferSize!=0) ?
738                    config.scratchBufferSize : (tempData.pipesUsed<<4));
739        else // new binaries
740            header.pipesUsage = 0;
741        header.unknown5[0] = header.unknown5[1] = 0;
742        SLEV(header.argsNum, argsNum);
743        fob.writeObject(header);
744        fob.fill(40, 0); // fill up
745        fob.writeObject(LEV(uint32_t(config.useEnqueue?1:0)));
746        fob.writeObject(LEV(uint32_t(kernelId)));
747        if (newBinaries) // additional data
748        {
749            fob.writeObject(LEV(uint32_t(0x00000006U)));
750            if (is16_3Ver)
751                fob.writeObject(uint32_t(0));
752            fob.writeObject(LEV(uint32_t(
753                        tempData.pipesUsed==0 && !config.useEnqueue ? 0xffffffffU : 0)));
754        }
755        if (is16_3Ver)
756            fob.fill(44, 0);
757        // two null terminated strings
758        fob.writeArray(22, "__OpenCL_dummy_kernel");
759        fob.writeArray(8, "generic");
760        if (is16_3Ver)
761            fob.writeObject<cxbyte>(0);
762       
763        // put argument entries
764        cxuint argOffset = 0;
765        for (cxuint i = 0; i < argsNum; i++)
766        {   //
767            const AmdKernelArgInput& arg = config.args[i];
768            AmdCL2GPUKernelArgEntry argEntry;
769            SLEV(argEntry.size, 88);
770            SLEV(argEntry.argNameSize, arg.argName.size());
771            SLEV(argEntry.typeNameSize, arg.typeName.size());
772            argEntry.unknown1 = 0;
773            argEntry.unknown2 = 0;
774           
775            const bool isImage = isKernelArgImage(arg.argType);
776           
777            const ArgTypeSizes& argTypeSizes = argTypeSizesTable[cxuint(arg.argType)];
778            cxuint vectorLength = argTypeSizes.vectorSize;
779            if (newBinaries && vectorLength==3)
780                vectorLength = 4;
781            if (isImage || arg.argType==KernelArgType::SAMPLER)
782                // image/sampler resid
783                SLEV(argEntry.resId, tempData.argResIds[i]);
784            else if (arg.argType == KernelArgType::STRUCTURE)
785                SLEV(argEntry.structSize, arg.structSize);
786            else
787                SLEV(argEntry.vectorLength, vectorLength);
788            size_t argSize = (arg.argType==KernelArgType::STRUCTURE) ? arg.structSize :
789                    // argSize for argOffset: clamp elem size to 4 bytes
790                    std::max(cxbyte(4), argTypeSizes.elemSize)*vectorLength;
791           
792            SLEV(argEntry.unknown3, (arg.argType!=KernelArgType::SAMPLER));
793            SLEV(argEntry.argOffset, argOffset);
794            argOffset += (argSize + 15) & ~15U; // align to 16 bytes
795           
796            uint32_t argType = 0;
797            if (isImage)
798            {   // if image
799                cxuint ptrAccMask = arg.ptrAccess & KARG_PTR_ACCESS_MASK;
800                argType = ptrAccMask==KARG_PTR_READ_ONLY ? 1 :
801                        ptrAccMask==KARG_PTR_WRITE_ONLY ? 2 : 3 /* read-write */;
802            }
803            else // otherwise
804            {
805                argType = argTypeSizes.type;
806                if (is16_3Ver && (arg.argType==KernelArgType::CHAR ||
807                     arg.argType==KernelArgType::SHORT ||
808                     arg.argType==KernelArgType::INT||
809                     arg.argType==KernelArgType::LONG))
810                    argType -= 4; // fix for crimson 16.4/gpupro
811            }
812            SLEV(argEntry.argType, argType);
813           
814            uint32_t ptrAlignment = 0;
815            if (arg.argType == KernelArgType::CMDQUEUE)
816                ptrAlignment = newBinaries ? 4 : 2;
817            else if (arg.argType == KernelArgType::PIPE)
818                ptrAlignment = 256;
819            else if (arg.argType == KernelArgType::CLKEVENT)
820                ptrAlignment = 4;
821            else if (isImage)
822                ptrAlignment = 1;
823            else if (arg.argType == KernelArgType::POINTER) // otherwise
824            {
825                cxuint vectorLength = argTypeSizesTable[cxuint(arg.pointerType)].vectorSize;
826                if (newBinaries && vectorLength==3)
827                vectorLength = 4;
828                size_t ptrTypeSize = (arg.pointerType==KernelArgType::STRUCTURE) ?
829                    arg.structSize :argTypeSizesTable[cxuint(arg.pointerType)].elemSize *
830                    vectorLength;
831                ptrAlignment = 1U<<(31-CLZ32(ptrTypeSize));
832                if (ptrAlignment != ptrTypeSize)
833                    ptrAlignment <<= 1;
834            }
835           
836            SLEV(argEntry.ptrAlignment, ptrAlignment);
837           
838            if (arg.argType == KernelArgType::CLKEVENT)
839            {
840                SLEV(argEntry.ptrType, 18);
841                SLEV(argEntry.ptrSpace, 4);
842            }
843            else if (arg.argType == KernelArgType::POINTER)
844            {
845                SLEV(argEntry.ptrType, argTypeSizesTable[cxuint(arg.pointerType)].type);
846                SLEV(argEntry.ptrSpace, ptrSpacesTable[cxuint(arg.ptrSpace)]);
847            }
848            else if (arg.argType == KernelArgType::PIPE)
849            {
850                SLEV(argEntry.ptrType, 15);
851                SLEV(argEntry.ptrSpace, 4);
852            }
853            else
854            {
855                argEntry.ptrType = 0;
856                argEntry.ptrSpace = 0;
857            }
858            cxuint isPointerOrPipe = 0;
859            if (arg.argType==KernelArgType::PIPE)
860                isPointerOrPipe = (arg.used) ? 3 : 1;
861            else if (arg.argType==KernelArgType::POINTER ||
862                    arg.argType==KernelArgType::CLKEVENT)
863            {
864                if (newBinaries)
865                    isPointerOrPipe = (arg.used!=0) ? arg.used : 1;
866                else // ???
867                    isPointerOrPipe = 3;
868            }
869            SLEV(argEntry.isPointerOrPipe, isPointerOrPipe);
870           
871            SLEV(argEntry.isConst, (arg.ptrAccess & KARG_PTR_CONST) != 0);
872            argEntry.isVolatile = ((arg.ptrAccess & KARG_PTR_VOLATILE) != 0);
873            argEntry.isRestrict = ((arg.ptrAccess & KARG_PTR_RESTRICT) != 0);
874            argEntry.unknown4 = 0;
875            argEntry.isPipe = (arg.argType==KernelArgType::PIPE);
876           
877            uint32_t kindOfType;
878            if (arg.argType==KernelArgType::SAMPLER)
879                kindOfType = 1;
880            else if (isImage)
881                kindOfType = 2;
882            else if (isPointerOrPipe)
883                kindOfType = 5;
884            else if (arg.argType==KernelArgType::CMDQUEUE)
885                kindOfType = 7;
886            else // otherwise
887                kindOfType = 4;
888            SLEV(argEntry.kindOfType, kindOfType);
889            SLEV(argEntry.unknown5, 0);
890            fob.writeObject(argEntry);
891        }
892        fob.fill(88, 0); // NULL arg
893       
894        // arg names and type names
895        for (const AmdKernelArgInput& arg: config.args)
896        {
897            fob.writeArray(arg.argName.size()+1, arg.argName.c_str());
898            fob.writeArray(arg.typeName.size()+1, arg.typeName.c_str());
899        }
900        fob.fill(48, 0);
901    }
902   
903    void operator()(FastOutputBuffer& fob) const
904    {
905        const bool newBinaries = input->driverVersion >= 191205;
906        for (size_t i = 0; i < input->kernels.size(); i++)
907        {
908            const AmdCL2KernelInput& kernel = input->kernels[i];
909            if (kernel.useConfig)
910                writeMetadata(i, tempDatas[i], kernel.config, fob);
911            else
912                fob.writeArray(kernel.metadataSize, kernel.metadata);
913        }
914        if (!newBinaries)
915            for (const AmdCL2KernelInput& kernel: input->kernels)
916            {
917                if (kernel.isaMetadata!=nullptr)
918                    fob.writeArray(kernel.isaMetadataSize, kernel.isaMetadata);
919                else // default values
920                    fob.writeArray(sizeof(kernelIsaMetadata), kernelIsaMetadata);
921            }
922    }
923};
924
925static const cxbyte kernelSetupBytesAfter8[40] =
926{
927    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
928    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
930    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
931    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
932};
933
934struct CLRX_INTERNAL IntAmdCL2SetupData
935{
936    uint32_t pgmRSRC1;
937    uint32_t pgmRSRC2;
938    uint16_t setup1;
939    uint16_t archInd;
940    uint32_t scratchBufferSize;
941    uint32_t localSize; // in bytes
942    uint32_t zero1;
943    uint32_t kernelArgsSize;
944    uint32_t zeroes[2];
945    uint16_t sgprsNumAll;
946    uint16_t vgprsNum16;
947    uint32_t vgprsNum;
948    uint32_t sgprsNum;
949    uint32_t zero3;
950    uint32_t setup2; // ??
951};
952
953static uint32_t calculatePgmRSRC2(const AmdCL2KernelConfig& config,
954                  bool storeLocalSize = false)
955{
956    uint32_t dimValues = 0;
957    if (config.dimMask != BINGEN_DEFAULT)
958    {
959        dimValues = ((config.dimMask&7)<<7);
960        if (!config.useEnqueue)
961            dimValues |= (((config.dimMask&4) ? 2 : (config.dimMask&2) ? 1 : 0)<<11);
962        else // enqueue needs TIDIG_COMP_CNT=2 ????
963            dimValues |= (2U<<11);
964    }
965    else
966        dimValues |= (config.pgmRSRC2 & 0x1b80U);
967   
968    const uint32_t localPart = (storeLocalSize) ? (((config.localSize+511)>>9)<<15) : 0;
969   
970    cxuint userDatasNum = 4;
971    if (config.useGeneric)
972        userDatasNum = 12;
973    else if (config.useEnqueue)
974        userDatasNum = 10;
975    else if (config.useSetup)
976        userDatasNum = 8;
977    else if (config.useArgs)
978        userDatasNum = 6;
979    return (config.pgmRSRC2 & 0xffffe440U) | (userDatasNum<<1) |
980            ((config.tgSize) ? 0x400 : 0) | ((config.scratchBufferSize)?1:0) | dimValues |
981            (uint32_t(config.exceptions)<<24) | localPart;
982}
983
984static void generateKernelSetup(GPUArchitecture arch, const AmdCL2KernelConfig& config,
985                FastOutputBuffer& fob, bool newBinaries, bool useLocals, bool usePipes)
986{
987    fob.writeObject<uint64_t>(LEV(uint64_t(newBinaries ? 0x100000001ULL : 1ULL)));
988    fob.writeArray(40, kernelSetupBytesAfter8);
989    IntAmdCL2SetupData setupData;
990    const cxuint neededExtraSGPRsNum = arch==GPUArchitecture::GCN1_2 ? 4 : 2;
991    const cxuint extraSGPRsNum = (config.useEnqueue || config.useGeneric) ?
992                neededExtraSGPRsNum : 0;
993    cxuint sgprsNum = std::max(config.usedSGPRsNum + extraSGPRsNum + 2, 1U);
994    cxuint vgprsNum = std::max(config.usedVGPRsNum, 1U);
995    // pgmrsrc1
996    SLEV(setupData.pgmRSRC1, config.pgmRSRC1 | ((vgprsNum-1)>>2) |
997            (((sgprsNum-1)>>3)<<6) | ((uint32_t(config.floatMode)&0xff)<<12) |
998            (newBinaries ? (1U<<21) : 0) /*dx11_clamp */ |
999            (config.ieeeMode?1U<<23:0) | (uint32_t(config.priority&3)<<10) |
1000            (config.privilegedMode?1U<<20:0) | (config.dx10Clamp?1U<<21:0) |
1001            (config.debugMode?1U<<22:0));
1002    // pgmrsrc2 - without ldssize
1003    uint16_t setup1 = 0x1;
1004    if (config.useGeneric)
1005        setup1 = 0x2f;
1006    else if (config.useEnqueue)
1007        setup1 = 0x2b;
1008    else if (config.useSetup)
1009        setup1 = 0xb;
1010    else if (config.useArgs)
1011        setup1 = 0x9;
1012   
1013    SLEV(setupData.pgmRSRC2, calculatePgmRSRC2(config));
1014   
1015    SLEV(setupData.setup1, setup1);
1016    SLEV(setupData.archInd, (arch==GPUArchitecture::GCN1_2 && newBinaries) ? 0x4a : 0x0a);
1017    SLEV(setupData.scratchBufferSize, config.scratchBufferSize);
1018    SLEV(setupData.localSize, config.localSize);
1019    setupData.zero1 = 0;
1020    setupData.zeroes[0] = setupData.zeroes[1] = 0;
1021    setupData.zero3 = 0;
1022   
1023    cxuint kernelArgSize = 0;
1024    for (const AmdKernelArgInput arg: config.args)
1025    {
1026        if (arg.argType == KernelArgType::POINTER ||
1027            arg.argType == KernelArgType::PIPE ||
1028            arg.argType == KernelArgType::CLKEVENT ||
1029            arg.argType == KernelArgType::STRUCTURE ||
1030            arg.argType == KernelArgType::CMDQUEUE ||
1031            arg.argType == KernelArgType::SAMPLER || isKernelArgImage(arg.argType))
1032        {
1033            if ((kernelArgSize&7)!=0)    // alignment
1034                kernelArgSize += 8-(kernelArgSize&7);
1035            kernelArgSize += 8;
1036        }
1037        else
1038        {   // scalar
1039            const ArgTypeSizes& argTypeSizes = argTypeSizesTable[cxuint(arg.argType)];
1040            cxuint vectorLength = argTypeSizes.vectorSize;
1041            if (newBinaries && vectorLength==3)
1042                vectorLength = 4;
1043            if ((kernelArgSize & (argTypeSizes.elemSize-1))!=0)
1044                kernelArgSize += argTypeSizes.elemSize -
1045                        (kernelArgSize & (argTypeSizes.elemSize-1));
1046            kernelArgSize += vectorLength * argTypeSizes.elemSize;
1047        }
1048    }
1049    if (newBinaries)
1050        kernelArgSize = (kernelArgSize+15)&~15U;
1051    SLEV(setupData.kernelArgsSize, kernelArgSize);
1052    SLEV(setupData.sgprsNumAll, sgprsNum);
1053    SLEV(setupData.vgprsNum16, config.usedVGPRsNum);
1054    SLEV(setupData.vgprsNum, config.usedVGPRsNum);
1055    SLEV(setupData.sgprsNum, config.usedSGPRsNum);
1056    if (newBinaries)
1057        SLEV(setupData.setup2, 0x06040404U);
1058    else // old binaries
1059    {
1060        uint32_t extraBits = (config.useEnqueue) ? 0x30000U : 0;
1061        extraBits |= (!config.useEnqueue && config.scratchBufferSize!=0) ? 0x40000U : 0;
1062        extraBits |= (config.localSize!=0) ? 0x200U : 0;
1063        extraBits |= (usePipes && (extraBits&0x40000U)==0) ? 0x30000U : 0;
1064        SLEV(setupData.setup2, 0x06000003U | extraBits);
1065    }
1066   
1067    fob.writeObject(setupData);
1068    fob.fill(256 - sizeof(IntAmdCL2SetupData) - 48, 0);
1069}
1070
1071struct CLRX_INTERNAL IntAmdCL2StubHeader
1072{
1073    uint32_t hsaTextOffset;
1074    uint32_t instrsNum;
1075    uint32_t vgprsNum;
1076    uint32_t zeroes[6];
1077    uint32_t sizeProgVal; // 0x24
1078    uint32_t globalMemOps;
1079    uint32_t localMemOps;
1080    uint32_t zero2;
1081    uint32_t programRegSize; // sum??
1082    uint32_t zero3;
1083    uint32_t sgprsNumAll;
1084};
1085
1086static const bool gcnSize11Table[16] =
1087{
1088    false, // GCNENC_SMRD, // 0000
1089    false, // GCNENC_SMRD, // 0001
1090    false, // GCNENC_VINTRP, // 0010
1091    false, // GCNENC_NONE, // 0011 - illegal
1092    true,  // GCNENC_VOP3A, // 0100
1093    false, // GCNENC_NONE, // 0101 - illegal
1094    true,  // GCNENC_DS,   // 0110
1095    true,  // GCNENC_FLAT, // 0111
1096    true,  // GCNENC_MUBUF, // 1000
1097    false, // GCNENC_NONE,  // 1001 - illegal
1098    true,  // GCNENC_MTBUF, // 1010
1099    false, // GCNENC_NONE,  // 1011 - illegal
1100    true,  // GCNENC_MIMG,  // 1100
1101    false, // GCNENC_NONE,  // 1101 - illegal
1102    true,  // GCNENC_EXP,   // 1110
1103    false  // GCNENC_NONE   // 1111 - illegal
1104};
1105
1106static const bool gcnSize12Table[16] =
1107{
1108    true,  // GCNENC_SMEM, // 0000
1109    true,  // GCNENC_EXP, // 0001
1110    false, // GCNENC_NONE, // 0010 - illegal
1111    false, // GCNENC_NONE, // 0011 - illegal
1112    true,  // GCNENC_VOP3A, // 0100
1113    false, // GCNENC_VINTRP, // 0101
1114    true,  // GCNENC_DS,   // 0110
1115    true,  // GCNENC_FLAT, // 0111
1116    true,  // GCNENC_MUBUF, // 1000
1117    false, // GCNENC_NONE,  // 1001 - illegal
1118    true,  // GCNENC_MTBUF, // 1010
1119    false, // GCNENC_NONE,  // 1011 - illegal
1120    true,  // GCNENC_MIMG,  // 1100
1121    false, // GCNENC_NONE,  // 1101 - illegal
1122    false, // GCNENC_NONE,  // 1110 - illegal
1123    false  // GCNENC_NONE   // 1111 - illegal
1124};
1125
1126enum : cxbyte
1127{
1128    INSTRTYPE_OTHER = 0,
1129    INSTRTYPE_GLOBAL,
1130    INSTRTYPE_LOCAL,
1131};
1132
1133static const cxbyte gcnEncInstrTable[16] =
1134{
1135    INSTRTYPE_OTHER, // 0000
1136    INSTRTYPE_OTHER, // 0001
1137    INSTRTYPE_OTHER, // 0010
1138    INSTRTYPE_OTHER, // 0011 - illegal
1139    INSTRTYPE_OTHER, // 0100
1140    INSTRTYPE_OTHER, // 0101 - illegal
1141    INSTRTYPE_LOCAL,  // 0110
1142    INSTRTYPE_GLOBAL, // 0111
1143    INSTRTYPE_GLOBAL, // 1000
1144    INSTRTYPE_OTHER,  // 1001 - illegal
1145    INSTRTYPE_GLOBAL, // 1010
1146    INSTRTYPE_OTHER,  // 1011 - illegal
1147    INSTRTYPE_GLOBAL, // 1100
1148    INSTRTYPE_OTHER,  // 1101 - illegal
1149    INSTRTYPE_OTHER,  // 1110
1150    INSTRTYPE_OTHER // 1111 - illegal
1151};
1152
1153/* count number of instructions, local memory operations and global memory operations */
1154
1155static void analyzeCode(GPUArchitecture arch, size_t codeSize, const cxbyte* code,
1156            IntAmdCL2StubHeader& stubHdr)
1157{
1158    uint32_t instrsNum = 0;
1159    uint32_t globalMemOps = 0;
1160    uint32_t localMemOps = 0;
1161    const size_t codeWordsNum = codeSize>>2;
1162    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(code);
1163    bool isGCN12 = (arch == GPUArchitecture::GCN1_2);
1164    bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
1165   
1166    /* main analyzing code loop, parse and determine instr encoding, and counts
1167     * global/local memory ops */
1168    for (size_t pos = 0; pos < codeWordsNum; instrsNum++)
1169    {
1170        uint32_t insnCode = ULEV(codeWords[pos++]);
1171       
1172        if ((insnCode & 0x80000000U) != 0)
1173        {
1174            if ((insnCode & 0x40000000U) == 0)
1175            {   // SOP???
1176                if  ((insnCode & 0x30000000U) == 0x30000000U)
1177                {   // SOP1/SOPK/SOPC/SOPP
1178                    const uint32_t encPart = (insnCode & 0x0f800000U);
1179                    if (encPart == 0x0e800000U)
1180                    {   // SOP1
1181                        if ((insnCode&0xff) == 0xff) // literal
1182                        {
1183                            if (pos < codeWordsNum) pos++;
1184                        }
1185                    }
1186                    else if (encPart == 0x0f000000U)
1187                    {   // SOPC
1188                        if ((insnCode&0xff) == 0xff ||
1189                            (insnCode&0xff00) == 0xff00) // literal
1190                            if (pos < codeWordsNum) pos++;
1191                    }
1192                    else if (encPart != 0x0f800000U) // no SOPP
1193                    {
1194                        const uint32_t opcode = ((insnCode>>23)&0x1f);
1195                        if ((!isGCN12 && opcode == 21) ||
1196                            (isGCN12 && opcode == 20))
1197                            if (pos < codeWordsNum) pos++;
1198                    }
1199                }
1200                else
1201                {   // SOP2
1202                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
1203                        // literal
1204                        if (pos < codeWordsNum) pos++;
1205                }
1206            }
1207            else
1208            {   // SMRD and others
1209                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
1210                if ((!isGCN12 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
1211                    (isGCN12 && gcnSize12Table[encPart]))
1212                {
1213                    if (pos < codeWordsNum) pos++;
1214                }
1215                cxbyte instrType = gcnEncInstrTable[encPart];
1216                if (instrType == INSTRTYPE_LOCAL)
1217                    localMemOps++;
1218                if (instrType == INSTRTYPE_GLOBAL)
1219                    globalMemOps++;
1220            }
1221        }
1222        else
1223        {   // some vector instructions
1224            if ((insnCode & 0x7e000000U) == 0x7c000000U)
1225            {   // VOPC
1226                if ((insnCode&0x1ff) == 0xff || // literal
1227                    // SDWA, DDP
1228                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
1229                {
1230                    if (pos < codeWordsNum) pos++;
1231                }
1232            }
1233            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
1234            {   // VOP1
1235                if ((insnCode&0x1ff) == 0xff || // literal
1236                    // SDWA, DDP
1237                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
1238                    if (pos < codeWordsNum) pos++;
1239            }
1240            else
1241            {   // VOP2
1242                const cxuint opcode = (insnCode >> 25)&0x3f;
1243                if ((!isGCN12 && (opcode == 32 || opcode == 33)) ||
1244                    (isGCN12 && (opcode == 23 || opcode == 24 ||
1245                    opcode == 36 || opcode == 37))) // V_MADMK and V_MADAK
1246                {
1247                    if (pos < codeWordsNum) pos++;
1248                }
1249                else if ((insnCode&0x1ff) == 0xff || // literal
1250                    // SDWA, DDP
1251                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
1252                    if (pos < codeWordsNum) pos++; 
1253            }
1254        }
1255    }
1256   
1257    SLEV(stubHdr.instrsNum, instrsNum);
1258    SLEV(stubHdr.localMemOps, localMemOps);
1259    SLEV(stubHdr.globalMemOps, globalMemOps);
1260}
1261
1262struct CLRX_INTERNAL IntAmdCL2StubEnd
1263{
1264    uint64_t hsaTextOffset;
1265    uint32_t endSize;
1266    uint32_t hsaTextSize;
1267    uint32_t zeroes[2];
1268    uint32_t unknown1; // value - 0x200
1269    uint32_t unknown2;
1270    uint64_t kernelSize;    // 0x20
1271    uint32_t zeroesx[2];
1272    uint64_t kernelSize2;
1273    uint32_t vgprsNum;      // 0x30
1274    uint32_t sgprsNumAll;
1275    uint32_t zeroes2[2];
1276    uint32_t vgprsNum2;
1277    uint32_t sgprsNum;
1278    uint32_t floatMode; // 0x50
1279    uint32_t unknown3;
1280    uint32_t one; //??
1281    uint32_t zeroes3[3];   
1282    uint32_t scratchBufferSize; // 0x68
1283    uint32_t localSize;
1284    uint32_t allOnes;// 0x70
1285    uint32_t unknownlast; // 0x74 (alignment)
1286};
1287
1288static void generateKernelStub(GPUArchitecture arch, const AmdCL2KernelConfig& config,
1289        FastOutputBuffer& fob, size_t codeSize, const cxbyte* code, bool useLocals,
1290        bool usePipes)
1291{
1292    const cxuint neededExtraSGPRsNum = arch==GPUArchitecture::GCN1_2 ? 4 : 2;
1293    const cxuint extraSGPRsNum = (config.useEnqueue) ? neededExtraSGPRsNum : 0;
1294    cxuint sgprsNumAll = config.usedSGPRsNum+2 + extraSGPRsNum;
1295    {
1296        IntAmdCL2StubHeader stubHdr;
1297        SLEV(stubHdr.hsaTextOffset, 0xa60);
1298        SLEV(stubHdr.instrsNum, 0xa60);
1299        SLEV(stubHdr.sgprsNumAll, sgprsNumAll);
1300        SLEV(stubHdr.vgprsNum, config.usedVGPRsNum);
1301        analyzeCode(arch, codeSize, code, stubHdr);
1302        std::fill(stubHdr.zeroes, stubHdr.zeroes+6, uint32_t(0));
1303        stubHdr.zero2 = 0;
1304        stubHdr.zero3 = 0;
1305        stubHdr.sizeProgVal = stubHdr.instrsNum; // this same? enough reliable?
1306        SLEV(stubHdr.programRegSize, config.usedSGPRsNum + config.usedVGPRsNum);
1307        fob.writeObject(stubHdr);
1308    }
1309    // next bytes
1310    fob.fill(0xb8 - sizeof(IntAmdCL2StubHeader), 0); // fill up
1311    fob.writeObject(LEV(0xa60));
1312    fob.fill(0x164-0xbc, 0); // fill up
1313    // 0x164
1314    fob.writeObject(LEV(3)); //?
1315    fob.writeObject(LEV(config.localSize!=0 ? 13 : 12)); //?
1316    fob.fill(0x9a0-0x16c, 0); // fill up
1317    { // end of stub - kernel config?
1318        IntAmdCL2StubEnd stubEnd;
1319        SLEV(stubEnd.hsaTextOffset, 0xa60);
1320        SLEV(stubEnd.endSize, 0x100);
1321        SLEV(stubEnd.hsaTextSize, codeSize + 0x100);
1322        stubEnd.zeroes[0] = stubEnd.zeroes[1] = 0;
1323        SLEV(stubEnd.unknown1, 0x200);
1324        stubEnd.unknown2 = 0;
1325        SLEV(stubEnd.kernelSize, codeSize + 0xb60);
1326        stubEnd.zeroesx[0] = stubEnd.zeroesx[1] = 0;
1327        SLEV(stubEnd.kernelSize2, codeSize + 0xb60);
1328        SLEV(stubEnd.vgprsNum, config.usedVGPRsNum);
1329        SLEV(stubEnd.sgprsNumAll, sgprsNumAll);
1330        SLEV(stubEnd.vgprsNum2, config.usedVGPRsNum);
1331        stubEnd.zeroes2[0] = stubEnd.zeroes2[1] = 0;
1332        SLEV(stubEnd.sgprsNum, config.usedSGPRsNum);
1333        SLEV(stubEnd.floatMode, config.floatMode&0xff);
1334        stubEnd.unknown3 = 0;
1335        SLEV(stubEnd.one, 1);
1336        stubEnd.zeroes3[0] = stubEnd.zeroes3[1] = stubEnd.zeroes3[2] = 0;
1337        SLEV(stubEnd.scratchBufferSize, (config.scratchBufferSize+3)>>2);
1338        SLEV(stubEnd.localSize, config.localSize);
1339        SLEV(stubEnd.allOnes, 0xffffffffU);
1340        SLEV(stubEnd.unknownlast, 0);
1341        fob.writeObject(stubEnd);
1342    }
1343    fob.fill(0xa8-sizeof(IntAmdCL2StubEnd), 0);
1344    fob.writeObject(LEV(calculatePgmRSRC2(config, true)));
1345    fob.fill(0xc0-0xac, 0);
1346}
1347
1348class CLRX_INTERNAL CL2MainTextGen: public ElfRegionContent
1349{
1350private:
1351    const AmdCL2Input* input;
1352    const Array<TempAmdCL2KernelData>& tempDatas;
1353    ElfBinaryGen64* innerBinGen;
1354public:
1355    explicit CL2MainTextGen(const AmdCL2Input* _input,
1356            const Array<TempAmdCL2KernelData>& _tempDatas,
1357            ElfBinaryGen64* _innerBinGen) : input(_input), tempDatas(_tempDatas),
1358            innerBinGen(_innerBinGen)
1359    { }
1360   
1361    size_t size() const
1362    {
1363        if (innerBinGen)
1364            return innerBinGen->countSize();
1365        size_t out = 0;
1366        for (const TempAmdCL2KernelData tempData: tempDatas)
1367            out += tempData.stubSize + tempData.setupSize + tempData.codeSize;
1368        return out;
1369    }
1370   
1371    void operator()(FastOutputBuffer& fob) const
1372    {
1373        if (innerBinGen!=nullptr)
1374            innerBinGen->generate(fob);
1375        else // otherwise (old binaries)
1376        {
1377            GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
1378            for (size_t i = 0; i < input->kernels.size(); i++)
1379            {
1380                const AmdCL2KernelInput& kernel = input->kernels[i];
1381                const TempAmdCL2KernelData& tempData = tempDatas[i];
1382                if (!kernel.useConfig)
1383                {   // no configuration, get from kernel data
1384                    fob.writeArray(tempData.stubSize, kernel.stub);
1385                    fob.writeArray(tempData.setupSize, kernel.setup);
1386                }
1387                else // generate stub, setup from kernel config
1388                {
1389                    generateKernelStub(arch, kernel.config, fob, tempData.codeSize,
1390                               kernel.code, tempData.useLocals, tempData.pipesUsed!=0);
1391                    generateKernelSetup(arch, kernel.config, fob, false,
1392                                tempData.useLocals, tempData.pipesUsed!=0);
1393                }
1394                fob.writeArray(kernel.codeSize, kernel.code);
1395            }
1396        }
1397    }
1398};
1399
1400class CLRX_INTERNAL CL2InnerTextGen: public ElfRegionContent
1401{
1402private:
1403    const AmdCL2Input* input;
1404    const Array<TempAmdCL2KernelData>& tempDatas;
1405public:
1406    explicit CL2InnerTextGen(const AmdCL2Input* _input,
1407                const Array<TempAmdCL2KernelData>& _tempDatas) : input(_input),
1408                tempDatas(_tempDatas)
1409    { }
1410   
1411    size_t size() const
1412    {
1413        size_t out = 0;
1414        for (const TempAmdCL2KernelData& tempData: tempDatas)
1415        {
1416            if ((out & 255) != 0)
1417                out += 256-(out&255);
1418            out += tempData.setupSize + tempData.codeSize;
1419        }
1420        return out;
1421    }
1422   
1423    void operator()(FastOutputBuffer& fob) const
1424    {
1425        GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
1426        size_t outSize = 0;
1427        for (size_t i = 0; i < input->kernels.size(); i++)
1428        {
1429            const AmdCL2KernelInput& kernel = input->kernels[i];
1430            const TempAmdCL2KernelData& tempData = tempDatas[i];
1431            if ((outSize & 255) != 0)
1432            {
1433                size_t toFill = 256-(outSize&255);
1434                fob.fill(toFill, 0);
1435                outSize += toFill;
1436            }
1437            if (!kernel.useConfig)
1438                fob.writeArray(tempData.setupSize, kernel.setup);
1439            else
1440                generateKernelSetup(arch, kernel.config, fob, true, tempData.useLocals,
1441                            tempData.pipesUsed!=0);
1442            fob.writeArray(tempData.codeSize, kernel.code);
1443            outSize += tempData.setupSize + tempData.codeSize;
1444        }
1445    }
1446};
1447
1448class CLRX_INTERNAL CL2InnerSamplerInitGen: public ElfRegionContent
1449{
1450private:
1451    const AmdCL2Input* input;
1452public:
1453    explicit CL2InnerSamplerInitGen(const AmdCL2Input* _input) : input(_input)
1454    { }
1455   
1456    void operator()(FastOutputBuffer& fob) const
1457    {
1458        if (input->samplerConfig)
1459        {
1460            uint32_t sampDef[2];
1461            for (uint32_t sampler: input->samplers)
1462            {
1463                SLEV(sampDef[0], 0x10008);
1464                SLEV(sampDef[1], sampler);
1465                fob.writeArray(2, sampDef);
1466            }
1467        }
1468        else
1469            fob.writeArray(input->samplerInitSize, input->samplerInit);
1470    }
1471};
1472
1473class CLRX_INTERNAL CL2InnerGlobalDataGen: public ElfRegionContent
1474{
1475private:
1476    const AmdCL2Input* input;
1477public:
1478    explicit CL2InnerGlobalDataGen(const AmdCL2Input* _input) : input(_input)
1479    { }
1480   
1481    size_t size() const
1482    {
1483        if (input->driverVersion >= 200406)
1484            return input->globalDataSize;
1485        size_t rwDataSize = (input->rwData!=nullptr) ? input->rwDataSize : 0;
1486        size_t allSize = (input->globalDataSize + input->bssSize +
1487                rwDataSize + 255) & ~size_t(255);
1488        return allSize - rwDataSize - input->bssSize;
1489    }
1490   
1491    void operator()(FastOutputBuffer& fob) const
1492    {
1493        size_t gdataSize = size();
1494        fob.writeArray(input->globalDataSize, input->globalData);
1495        if (gdataSize > input->globalDataSize)
1496            fob.fill(gdataSize - input->globalDataSize, 0);
1497    }
1498};
1499
1500class CLRX_INTERNAL CL2InnerGlobalDataRelsGen: public ElfRegionContent
1501{
1502private:
1503    const AmdCL2Input* input;
1504    size_t dataSymbolsNum;
1505public:
1506    explicit CL2InnerGlobalDataRelsGen(const AmdCL2Input* _input, size_t _dataSymNum)
1507            : input(_input), dataSymbolsNum(_dataSymNum)
1508    { }
1509   
1510    size_t size() const
1511    {
1512        size_t out = (input->samplerConfig) ? input->samplers.size() :
1513                (input->samplerInitSize>>3);
1514        return out*sizeof(Elf64_Rela);
1515    }
1516   
1517    void operator()(FastOutputBuffer& fob) const
1518    {
1519        Elf64_Rela rela;
1520        rela.r_addend = 0;
1521        const size_t samplersNum = (input->samplerConfig) ?
1522                input->samplers.size() : (input->samplerInitSize>>3);
1523        /* calculate first symbol for samplers (last symbols) */
1524        uint32_t symIndex = input->kernels.size() + samplersNum + dataSymbolsNum + 2 +
1525                (input->rwDataSize!=0 && input->rwData!=nullptr) /* globaldata symbol */ +
1526                (input->bssSize!=0) /* bss data symbol */ +
1527                (input->driverVersion>=200406);
1528        if (!input->samplerOffsets.empty())
1529            for (size_t sampOffset: input->samplerOffsets)
1530            {
1531                SLEV(rela.r_offset, sampOffset);
1532                SLEV(rela.r_info, ELF64_R_INFO(symIndex, 4U));
1533                fob.writeObject(rela);
1534                symIndex++;
1535            }
1536        else // default in last bytes
1537        {
1538            size_t globalOffset = input->globalDataSize - (samplersNum<<3);
1539            globalOffset &= ~size_t(7); // alignment
1540            for (size_t i = 0; i < samplersNum; i++)
1541            {
1542                SLEV(rela.r_offset, globalOffset + 8*i);
1543                SLEV(rela.r_info, ELF64_R_INFO(symIndex+i, 4U));
1544                fob.writeObject(rela);
1545            }
1546        }
1547    }
1548};
1549
1550class CLRX_INTERNAL CL2InnerTextRelsGen: public ElfRegionContent
1551{
1552private:
1553    const AmdCL2Input* input;
1554    const Array<TempAmdCL2KernelData>& tempDatas;
1555    size_t dataSymbolsNum;
1556public:
1557    explicit CL2InnerTextRelsGen(const AmdCL2Input* _input,
1558            const Array<TempAmdCL2KernelData>& _tempDatas, size_t _dataSymNum) :
1559            input(_input), tempDatas(_tempDatas), dataSymbolsNum(_dataSymNum)
1560    { }
1561   
1562    size_t size() const
1563    {
1564        size_t out = 0;
1565        for (const AmdCL2KernelInput& kernel: input->kernels)
1566            out += kernel.relocations.size()*sizeof(Elf64_Rela);
1567        return out;
1568    }
1569   
1570    void operator()(FastOutputBuffer& fob) const
1571    {
1572        Elf64_Rela rela;
1573        size_t codeOffset = 0;
1574        uint32_t adataSymIndex = 0;
1575        cxuint samplersNum = (input->samplerConfig) ?
1576                input->samplers.size() : (input->samplerInitSize>>3);
1577        uint32_t gdataSymIndex = input->kernels.size() + samplersNum + dataSymbolsNum +
1578            (input->driverVersion>=200406);
1579        uint32_t bssSymIndex = input->kernels.size() + samplersNum + dataSymbolsNum +
1580            (input->driverVersion>=200406);
1581        if (input->rwDataSize!=0 && input->rwData!=nullptr)
1582        {   // atomic data available
1583            adataSymIndex = gdataSymIndex; // first is atomic data symbol index
1584            gdataSymIndex++;
1585        }
1586        if (input->bssSize!=0)
1587        {   // bss section available
1588            bssSymIndex = gdataSymIndex; // first is bss data symbol index
1589            gdataSymIndex++;
1590        }
1591        for (size_t i = 0; i < input->kernels.size(); i++)
1592        {
1593            const AmdCL2KernelInput& kernel = input->kernels[i];
1594            const TempAmdCL2KernelData& tempData = tempDatas[i];
1595           
1596            codeOffset += tempData.setupSize;
1597            for (const AmdCL2RelInput inRel: kernel.relocations)
1598            {
1599                SLEV(rela.r_offset, inRel.offset + codeOffset);
1600                uint32_t type = (inRel.type==RELTYPE_LOW_32BIT) ? 1 : 2;
1601                uint32_t symIndex = (inRel.symbol==1) ? adataSymIndex : 
1602                    ((inRel.symbol==2) ? bssSymIndex: gdataSymIndex);
1603                SLEV(rela.r_info, ELF64_R_INFO(symIndex, type));
1604                SLEV(rela.r_addend, inRel.addend);
1605                fob.writeObject(rela);
1606            }
1607            codeOffset += (kernel.codeSize+255)&~size_t(255);
1608        }
1609    }
1610};
1611
1612/* NT_VERSION (0x1): size: 8, value: 0x1
1613 * NT_ARCH (0x2): size: 12, dwords: 0x1, 0x0, 0x010101
1614 * 0x5: size: 25, string: \x16\000-hsa_call_convention=\0\0
1615 * 0x3: size: 30, string: (version???)
1616 * "\4\0\7\0\7\0\0\0\0\0\0\0\0\0\0\0AMD\0AMDGPU\0\0\0\0"
1617 * 0x4: size: 4, random 64-bit value: 0x7ffXXXXXXXXX */
1618static const cxbyte noteSectionData[168] =
1619{
1620    0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1621    0x01, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1622    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1623    0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1624    0x02, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1625    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1626    0x01, 0x01, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
1627    0x19, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1628    0x41, 0x4d, 0x44, 0x00, 0x16, 0x00, 0x2d, 0x68,
1629    0x73, 0x61, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f,
1630    0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69,
1631    0x6f, 0x6e, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00,
1632    0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
1633    0x03, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1634    0x04, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
1635    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1636    0x41, 0x4d, 0x44, 0x00, 0x41, 0x4d, 0x44, 0x47,
1637    0x50, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1638    0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1639    0x04, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1640    0xf0, 0x83, 0x17, 0xfb, 0xfc, 0x7f, 0x00, 0x00
1641};
1642
1643static const size_t noteAMDGPUTypeOffset = 0x74;
1644
1645static const cxbyte noteSectionData16_3[200] =
1646{
1647    0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
1648    0x01, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1649    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1650    0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
1651    0x02, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1652    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1653    0x01, 0x01, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
1654    0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1655    0x41, 0x4d, 0x44, 0x00, 0x04, 0x00, 0x07, 0x00,
1656    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1657    0x00, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1658    0x41, 0x4d, 0x44, 0x47, 0x50, 0x55, 0x00, 0x00,
1659    0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
1660    0x04, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x00,
1661    0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1662    0x00, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x44, 0x20,
1663    0x48, 0x53, 0x41, 0x20, 0x52, 0x75, 0x6e, 0x74,
1664    0x69, 0x6d, 0x65, 0x20, 0x46, 0x69, 0x6e, 0x61,
1665    0x6c, 0x69, 0x7a, 0x65, 0x72, 0x00, 0x00, 0x00,
1666    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1667    0x1a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1668    0x41, 0x4d, 0x44, 0x00, 0x16, 0x00, 0x2d, 0x68,
1669    0x73, 0x61, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f,
1670    0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69,
1671    0x6f, 0x6e, 0x3d, 0x30, 0x00, 0x00, 0x00, 0x00,
1672};
1673
1674static const size_t noteAMDGPUTypeOffset_16_3 = 0x48;
1675
1676struct AMDGPUArchValues
1677{
1678    uint32_t major;
1679    uint32_t minor;
1680    uint32_t stepping;
1681};
1682
1683/* TODO: add gpu values tables for various driver version */
1684static const AMDGPUArchValues amdGpuArchValuesTbl[] =
1685{
1686    { 0, 0, 0 }, // GPUDeviceType::CAPE_VERDE
1687    { 0, 0, 0 }, // GPUDeviceType::PITCAIRN
1688    { 0, 0, 0 }, // GPUDeviceType::TAHITI
1689    { 0, 0, 0 }, // GPUDeviceType::OLAND
1690    { 7, 0, 0 }, // GPUDeviceType::BONAIRE
1691    { 7, 0, 0 }, // GPUDeviceType::SPECTRE
1692    { 7, 0, 0 }, // GPUDeviceType::SPOOKY
1693    { 7, 0, 0 }, // GPUDeviceType::KALINDI
1694    { 0, 0, 0 }, // GPUDeviceType::HAINAN
1695    { 7, 0, 1 }, // GPUDeviceType::HAWAII
1696    { 8, 0, 0 }, // GPUDeviceType::ICELAND
1697    { 8, 0, 0 }, // GPUDeviceType::TONGA
1698    { 7, 0, 0 }, // GPUDeviceType::MULLINS
1699    { 8, 0, 4 }, // GPUDeviceType::FIJI
1700    { 8, 0, 1 }, // GPUDeviceType::CARRIZO
1701    { 0, 0, 0 }, // GPUDeviceType::DUMMY
1702    { 0, 0, 0 }, // GPUDeviceType::GOOSE
1703    { 0, 0, 0 }, // GPUDeviceType::HORSE
1704    { 8, 1, 0 }, // GPUDeviceType::STONEY
1705    { 8, 0, 4 }, // GPUDeviceType::ELLESMERE
1706    { 8, 0, 4 } // GPUDeviceType::BAFFIN
1707};
1708
1709static CString constructName(size_t prefixSize, const char* prefix, const CString& name,
1710                 size_t suffixSize, const char* suffix)
1711{
1712    const size_t nameLen = name.size();
1713    CString out(prefixSize + suffixSize + nameLen);
1714    char* outPtr = out.begin();
1715    std::copy(prefix, prefix+prefixSize, outPtr);
1716    std::copy(name.begin(), name.begin()+nameLen, outPtr+prefixSize);
1717    std::copy(suffix, suffix+suffixSize, outPtr+prefixSize+nameLen);
1718    return out;
1719}
1720
1721static void putInnerSymbols(ElfBinaryGen64& innerBinGen, const AmdCL2Input* input,
1722        const Array<TempAmdCL2KernelData>& tempDatas, const uint16_t* builtinSectionTable,
1723        cxuint extraSeciontIndex, std::vector<CString>& stringPool, size_t dataSymbolsNum)
1724{
1725    const size_t samplersNum = (input->samplerConfig) ? input->samplers.size() :
1726                (input->samplerInitSize>>3);
1727    // put kernel symbols
1728    std::vector<bool> samplerMask(samplersNum);
1729    size_t samplerOffset = input->globalDataSize - samplersNum;
1730    size_t codePos = 0;
1731    const uint16_t textSectId = builtinSectionTable[ELFSECTID_TEXT-ELFSECTID_START];
1732    const uint16_t globalSectId = builtinSectionTable[ELFSECTID_RODATA-ELFSECTID_START];
1733    const uint16_t atomicSectId = builtinSectionTable[
1734                ELFSECTID_DATA-ELFSECTID_START];
1735    const uint16_t sampInitSectId = builtinSectionTable[
1736                AMDCL2SECTID_SAMPLERINIT-ELFSECTID_START];
1737    const uint16_t bssSectId = builtinSectionTable[ELFSECTID_BSS-ELFSECTID_START];
1738    stringPool.resize(input->kernels.size() + samplersNum + dataSymbolsNum);
1739    size_t nameIdx = 0;
1740   
1741    /* put data symbols */
1742    for (const BinSymbol& symbol: input->innerExtraSymbols)
1743        if (symbol.sectionId==ELFSECTID_RODATA || symbol.sectionId==ELFSECTID_DATA ||
1744                   symbol.sectionId==ELFSECTID_BSS)
1745        {
1746            stringPool[nameIdx] = constructName(12, "&input_bc::&", symbol.name,
1747                        0, nullptr);
1748            innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(),
1749                  convertSectionId(symbol.sectionId, builtinSectionTable, AMDCL2SECTID_MAX,
1750                           extraSeciontIndex),
1751                  ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), 0, false, symbol.value, 
1752                  symbol.size));
1753            nameIdx++;
1754        }
1755    for (size_t i = 0; i < input->kernels.size(); i++)
1756    {   // first, we put sampler objects
1757        const AmdCL2KernelInput& kernel = input->kernels[i];
1758        const TempAmdCL2KernelData& tempData = tempDatas[i];
1759        if ((codePos & 255) != 0)
1760            codePos += 256-(codePos&255);
1761       
1762        if (kernel.useConfig)
1763            for (cxuint samp: kernel.config.samplers)
1764            {
1765                if (samplerMask[samp])
1766                    continue; // if added to symbol table
1767                const uint64_t value = !input->samplerOffsets.empty() ?
1768                        input->samplerOffsets[samp] : samplerOffset + samp*8;
1769                char sampName[64];
1770                memcpy(sampName, "&input_bc::&_.Samp", 18);
1771                itocstrCStyle<cxuint>(samp, sampName+18, 64-18);
1772                stringPool[nameIdx] = sampName;
1773                innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(), globalSectId,
1774                          ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), 0, false, value, 8));
1775                nameIdx++;
1776                samplerMask[samp] = true;
1777            }
1778        // put kernel symbol
1779        stringPool[nameIdx] = constructName(10, "&__OpenCL_", kernel.kernelName,
1780                        7, "_kernel");
1781       
1782        innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(), textSectId,
1783                  ELF64_ST_INFO(STB_GLOBAL, 10), 0, false, codePos, 
1784                  kernel.codeSize + tempData.setupSize));
1785        nameIdx++;
1786        codePos += kernel.codeSize + tempData.setupSize;
1787    }
1788   
1789    for (size_t i = 0; i < samplersNum; i++)
1790        if (!samplerMask[i])
1791        {
1792            const uint64_t value = !input->samplerOffsets.empty() ?
1793                    input->samplerOffsets[i] : samplerOffset + i*8;
1794            char sampName[64];
1795            memcpy(sampName, "&input_bc::&_.Samp", 18);
1796            itocstrCStyle<cxuint>(i, sampName+18, 64-18);
1797            stringPool[nameIdx] = sampName;
1798            innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(), globalSectId,
1799                      ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), 0, false, value, 8));
1800            nameIdx++;
1801            samplerMask[i] = true;
1802        }
1803   
1804    if (input->rwDataSize!=0 && input->rwData!=nullptr)
1805        innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsadata_global_agent",
1806              atomicSectId, ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1807    if (input->bssSize!=0)
1808        innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsabss_global_agent",
1809              bssSectId, ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1810    if (input->globalDataSize!=0 && input->globalData!=nullptr)
1811        innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsadata_readonly_agent",
1812              globalSectId, ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1813    innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsatext", textSectId,
1814              ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1815   
1816    for (size_t i = 0; i < samplersNum; i++)
1817        innerBinGen.addSymbol(ElfSymbol64("", sampInitSectId, ELF64_ST_INFO(STB_LOCAL, 12),
1818                      0, false, i*8, 0));
1819    /// add extra inner symbols
1820    for (const BinSymbol& extraSym: input->innerExtraSymbols)
1821        innerBinGen.addSymbol(ElfSymbol64(extraSym, builtinSectionTable, AMDCL2SECTID_MAX,
1822                                  extraSeciontIndex));
1823}
1824
1825/// main routine to generate OpenCL 2.0 binary
1826void AmdCL2GPUBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
1827             Array<cxbyte>* aPtr) const
1828{
1829    const size_t kernelsNum = input->kernels.size();
1830    const bool newBinaries = input->driverVersion >= 191205;
1831    const bool hasSamplers = !input->samplerOffsets.empty() ||
1832                (!input->samplerConfig && input->samplerInitSize!=0 &&
1833                    input->samplerInit!=nullptr) ||
1834                (input->samplerConfig && !input->samplers.empty());
1835    const bool hasGlobalData = input->globalDataSize!=0 && input->globalData!=nullptr;
1836    const bool hasRWData = input->rwDataSize!=0 && input->rwData!=nullptr;
1837   
1838    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
1839    if (arch == GPUArchitecture::GCN1_0)
1840        throw Exception("OpenCL 2.0 supported only for GCN1.1 or later");
1841   
1842    AMDGPUArchValues amdGpuArchValues = amdGpuArchValuesTbl[cxuint(input->deviceType)];
1843    if (input->archMinor!=UINT32_MAX)
1844        amdGpuArchValues.minor = input->archMinor;
1845    if (input->archStepping!=UINT32_MAX)
1846        amdGpuArchValues.stepping = input->archStepping;
1847   
1848    if ((hasGlobalData || hasRWData || hasSamplers) && !newBinaries)
1849        throw Exception("Old driver binaries doesn't support "
1850                        "global/atomic data or samplers");
1851   
1852    if (newBinaries)
1853    {
1854        if (!hasGlobalData && hasSamplers)
1855            throw Exception("Global data must be defined if samplers present");
1856        // check sampler offset range
1857        for (size_t sampOffset: input->samplerOffsets)
1858            if (sampOffset+8 > input->globalDataSize)
1859                throw Exception("Sampler offset outside global data");
1860    }
1861    /* check samplers */
1862    const cxuint samplersNum = (input->samplerConfig) ? input->samplers.size() :
1863                (input->samplerInitSize>>3);
1864    if (!input->samplerOffsets.empty() && input->samplerOffsets.size() != samplersNum)
1865        throw Exception("SamplerOffset number doesn't match to samplers number");
1866   
1867    for (size_t sampOffset: input->samplerOffsets)
1868        if ((sampOffset&7) != 0 && sampOffset >= input->globalDataSize)
1869            throw Exception("Wrong sampler offset (out of range of unaligned)");
1870   
1871    const bool gpuProDriver = (input->driverVersion == 203603 ||
1872            input->driverVersion == 207903);
1873    /* determine correct flags for device type */
1874    const uint32_t* deviceCodeTable;
1875    if (input->driverVersion < 191205)
1876        deviceCodeTable = gpuDeviceCodeTable15_7;
1877    else if (input->driverVersion < 200406)
1878        deviceCodeTable = gpuDeviceCodeTable;
1879    else if (input->driverVersion < 203603)
1880        deviceCodeTable = gpuDeviceCodeTable16_3;
1881    else // AMD GPUPRO driver and later
1882        deviceCodeTable = gpuDeviceCodeTableGPUPRO;
1883    // if GPU type is not supported by driver version
1884    if (deviceCodeTable[cxuint(input->deviceType)] == UINT_MAX)
1885        throw Exception("Unsupported GPU device type by driver version");
1886   
1887    ElfBinaryGen64 elfBinGen({ 0, 0, ELFOSABI_SYSV, 0, ET_EXEC, 0xaf5b, EV_CURRENT,
1888                UINT_MAX, 0, deviceCodeTable[cxuint(input->deviceType)] });
1889   
1890    CString aclVersion = input->aclVersion;
1891    if (aclVersion.empty())
1892    {
1893        if (newBinaries)
1894            aclVersion = "AMD-COMP-LIB-v0.8 (0.0.SC_BUILD_NUMBER)";
1895        else // old binaries
1896            aclVersion = "AMD-COMP-LIB-v0.8 (0.0.326)";
1897    }
1898   
1899    Array<TempAmdCL2KernelData> tempDatas(kernelsNum);
1900    prepareKernelTempData(input, tempDatas);
1901   
1902    const size_t dataSymbolsNum = std::count_if(input->innerExtraSymbols.begin(),
1903        input->innerExtraSymbols.end(), [](const BinSymbol& symbol)
1904        { return symbol.sectionId==ELFSECTID_RODATA || symbol.sectionId==ELFSECTID_DATA ||
1905                   symbol.sectionId==ELFSECTID_BSS; });
1906   
1907    cxuint mainExtraSectionIndex = 6 + (kernelsNum != 0 || newBinaries);
1908    CL2MainStrTabGen mainStrTabGen(input);
1909    CL2MainSymTabGen mainSymTabGen(input, tempDatas, aclVersion, mainExtraSectionIndex);
1910    CL2MainCommentGen mainCommentGen(input, aclVersion);
1911    CL2MainRodataGen mainRodataGen(input, tempDatas);
1912    CL2InnerTextGen innerTextGen(input, tempDatas);
1913    CL2InnerGlobalDataGen innerGDataGen(input);
1914    CL2InnerSamplerInitGen innerSamplerInitGen(input);
1915    CL2InnerTextRelsGen innerTextRelsGen(input, tempDatas, dataSymbolsNum);
1916    CL2InnerGlobalDataRelsGen innerGDataRels(input, dataSymbolsNum);
1917   
1918    // main section of main binary
1919    elfBinGen.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".shstrtab",
1920                    SHT_STRTAB, SHF_STRINGS));
1921    elfBinGen.addRegion(ElfRegion64(mainStrTabGen.size(), &mainStrTabGen, 1, ".strtab",
1922                    SHT_STRTAB, SHF_STRINGS));
1923    elfBinGen.addRegion(ElfRegion64(mainSymTabGen.size(), &mainSymTabGen, 8, ".symtab",
1924                    SHT_SYMTAB, 0));
1925    elfBinGen.addRegion(ElfRegion64(input->compileOptions.size()+aclVersion.size(),
1926                    &mainCommentGen, 1, ".comment", SHT_PROGBITS, 0));
1927    if (kernelsNum != 0)
1928        elfBinGen.addRegion(ElfRegion64(mainRodataGen.size(), &mainRodataGen, 1, ".rodata",
1929                    SHT_PROGBITS, SHF_ALLOC));
1930   
1931    std::unique_ptr<ElfBinaryGen64> innerBinGen;
1932    std::vector<CString> symbolNamePool;
1933    std::unique_ptr<cxbyte[]> noteBuf;
1934    if (newBinaries)
1935    {   // new binaries - .text holds inner ELF binaries
1936        bool is16_3Ver = (input->driverVersion>=200406);
1937        uint16_t innerBinSectionTable[innerBinSectonTableLen];
1938        cxuint extraSectionIndex = 1;
1939        /* check kernel text relocations */
1940        for (const AmdCL2KernelInput& kernel: input->kernels)
1941            for (const AmdCL2RelInput& rel: kernel.relocations)
1942                if (rel.offset >= kernel.codeSize)
1943                    throw Exception("Kernel text relocation offset outside kernel code");
1944       
1945        std::fill(innerBinSectionTable,
1946                  innerBinSectionTable+innerBinSectonTableLen, SHN_UNDEF);
1947       
1948        cxuint symtabId, globalDataId, textId;
1949        if (!is16_3Ver)
1950        {
1951            symtabId = 4 + (hasSamplers?2:0) /* samplerinit&rela.global */ +
1952                    (hasRWData) + (hasGlobalData) +
1953                    (input->bssSize!=0) +
1954                    (hasRWData || hasGlobalData || input->bssSize!=0) /* rela.hsatext */;
1955            globalDataId = 1 + (hasRWData) + (input->bssSize!=0);
1956            textId = 1 + (hasRWData) + (hasGlobalData) + (input->bssSize!=0);
1957        }
1958        else
1959        {
1960            textId = 4 + (hasRWData) + (hasGlobalData) + (input->bssSize!=0);
1961            symtabId = 5 + (hasRWData) + (hasGlobalData) + (input->bssSize!=0);
1962            globalDataId = 4 + (hasRWData) + (input->bssSize!=0);
1963        }
1964        /* in innerbin we do not add null symbol, we count address for program headers
1965         * and section from first section */
1966        innerBinGen.reset(new ElfBinaryGen64({ 0, 0, 0x40, 0, ET_REL, 0xe0, EV_CURRENT,
1967                        UINT_MAX, 0, 0 }, (input->driverVersion>=200406), true, true, 
1968                        /* globaldata sectionid: for 200406 - 4, for older - 1 */
1969                        (!is16_3Ver) ? 1 : 4));
1970        innerBinGen->addRegion(ElfRegion64::programHeaderTable());
1971       
1972        if (is16_3Ver)
1973        {   /* first is shstrab and strtab */
1974            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8, ".shstrtab",
1975                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
1976            innerBinSectionTable[ELFSECTID_SHSTRTAB-ELFSECTID_START] = extraSectionIndex++;
1977            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8, ".strtab",
1978                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
1979            innerBinSectionTable[ELFSECTID_STRTAB-ELFSECTID_START] = extraSectionIndex++;
1980           
1981            noteBuf.reset(new cxbyte[sizeof(noteSectionData16_3)]);
1982            ::memcpy(noteBuf.get(), noteSectionData16_3, sizeof(noteSectionData16_3));
1983            // set AMDGPU type
1984            /*
1985             * AMD - 1 - 00000001 00000000
1986             * AMD - 2 - 00000001 00000000 00010101
1987             * AMD - 3 - size=0x1a, 00070004 major minor stepping AMD\0 AMDGPU\0
1988             * AMD - 4 - size=0x29 00000019 00000001 00000000
1989             *      "AMD HSA Runtime Finalizer" 00000000
1990             * AMD - 5 - size=0x19 \x16\000-hsa_call_convention=\0\0
1991             */
1992            SULEV(*(uint32_t*)(noteBuf.get()+noteAMDGPUTypeOffset_16_3),
1993                  amdGpuArchValues.major);
1994            SULEV(*(uint32_t*)(noteBuf.get()+noteAMDGPUTypeOffset_16_3 + 4),
1995                  amdGpuArchValues.minor);
1996            SULEV(*(uint32_t*)(noteBuf.get()+noteAMDGPUTypeOffset_16_3 + 8),
1997                  amdGpuArchValues.stepping);
1998           
1999            if (gpuProDriver)
2000                noteBuf[197] = 't';
2001            innerBinGen->addRegion(ElfRegion64(sizeof(noteSectionData16_3),
2002                       noteBuf.get(), 8, ".note", SHT_NOTE, 0));
2003            innerBinSectionTable[AMDCL2SECTID_NOTE-ELFSECTID_START] = extraSectionIndex++;
2004        }
2005        if (hasRWData)
2006        {   // rw data section
2007            innerBinGen->addRegion(ElfRegion64(input->rwDataSize, input->rwData,
2008                      8, ".hsadata_global_agent", SHT_PROGBITS, 0x900003, 0, 0,
2009                      Elf64Types::nobase));
2010            innerBinSectionTable[ELFSECTID_DATA-ELFSECTID_START] =
2011                    extraSectionIndex++;
2012        }
2013        if (input->bssSize!=0)
2014        {
2015            innerBinGen->addRegion(ElfRegion64(input->bssSize, (const cxbyte*)nullptr,
2016                      input->bssAlignment!=0 ? input->bssAlignment : 8,
2017                      ".hsabss_global_agent", SHT_NOBITS, 0x900003,
2018                      0, 0, Elf64Types::nobase, 0, true));
2019            innerBinSectionTable[ELFSECTID_BSS-ELFSECTID_START] = extraSectionIndex++;
2020        }
2021        if (hasGlobalData)
2022        {// global data section
2023            innerBinGen->addRegion(ElfRegion64(innerGDataGen.size(), &innerGDataGen,
2024                      8, ".hsadata_readonly_agent", SHT_PROGBITS, 0xa00003, 0, 0,
2025                      Elf64Types::nobase));
2026            innerBinSectionTable[ELFSECTID_RODATA-ELFSECTID_START] = extraSectionIndex++;
2027        }
2028        if (kernelsNum != 0)
2029        {
2030            innerBinGen->addRegion(ElfRegion64(innerTextGen.size(), &innerTextGen, 256,
2031                      ".hsatext", SHT_PROGBITS, 0xc00007, 0, 0, 
2032                      Elf64Types::nobase, 0));
2033            innerBinSectionTable[ELFSECTID_TEXT-ELFSECTID_START] = extraSectionIndex++;
2034        }
2035       
2036        if (is16_3Ver)
2037        {   /* new driver version */
2038            innerBinGen->addRegion(ElfRegion64::symtabSection());
2039            innerBinSectionTable[ELFSECTID_SYMTAB-ELFSECTID_START] = extraSectionIndex++;
2040        }
2041       
2042        if (hasSamplers)
2043        {
2044            innerBinGen->addRegion(ElfRegion64(input->samplerConfig ?
2045                    input->samplers.size()*8 : input->samplerInitSize,
2046                    &innerSamplerInitGen, (is16_3Ver) ? 8 : 1,
2047                    ".hsaimage_samplerinit", SHT_PROGBITS, SHF_MERGE, 0, 0, 0, 8));
2048            innerBinSectionTable[AMDCL2SECTID_SAMPLERINIT-ELFSECTID_START] =
2049                        extraSectionIndex++;
2050            innerBinGen->addRegion(ElfRegion64(innerGDataRels.size(), &innerGDataRels,
2051                    8, ".rela.hsadata_readonly_agent", SHT_RELA, 0, symtabId,
2052                    globalDataId, 0, sizeof(Elf64_Rela)));
2053            innerBinSectionTable[AMDCL2SECTID_RODATARELA-ELFSECTID_START] =
2054                        extraSectionIndex++;
2055        }
2056        size_t textRelSize = innerTextRelsGen.size();
2057        if (textRelSize!=0) // if some relocations
2058        {
2059            innerBinGen->addRegion(ElfRegion64(textRelSize, &innerTextRelsGen, 8,
2060                    ".rela.hsatext", SHT_RELA, 0, symtabId, textId,  0,
2061                    sizeof(Elf64_Rela)));
2062            innerBinSectionTable[AMDCL2SECTID_TEXTRELA-ELFSECTID_START] =
2063                    extraSectionIndex++;
2064        }
2065       
2066        if (!is16_3Ver)
2067        {   /* this order of section for 1912.05 driver version */
2068            /* AMD - 1 - 00000001 00000000
2069             * AMD - 2 - 00000001 00000000 00010101
2070             * AMD - 5 - size=0x19 \x16\000-hsa_call_convention=\0\0
2071             * AMD - 3 - size=0x1e, 00070004 major minor stepping AMD\0 AMDGPU\0 00000000
2072             * AMD - 4 - size=8 random values 0x7ffXXXXXXXX
2073             */
2074            noteBuf.reset(new cxbyte[sizeof(noteSectionData)]);
2075            ::memcpy(noteBuf.get(), noteSectionData, sizeof(noteSectionData));
2076            // set AMDGPU type
2077            SULEV(*(uint32_t*)(noteBuf.get()+noteAMDGPUTypeOffset),
2078                  amdGpuArchValues.major);
2079            SULEV(*(uint32_t*)(noteBuf.get()+noteAMDGPUTypeOffset + 4),
2080                  amdGpuArchValues.minor);
2081            SULEV(*(uint32_t*)(noteBuf.get()+noteAMDGPUTypeOffset + 8),
2082                  amdGpuArchValues.stepping);
2083            innerBinGen->addRegion(ElfRegion64(sizeof(noteSectionData),
2084                       noteBuf.get(), 8, ".note", SHT_NOTE, 0));
2085           
2086            innerBinSectionTable[AMDCL2SECTID_NOTE-ELFSECTID_START] = extraSectionIndex++;
2087            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".strtab",
2088                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
2089            innerBinSectionTable[ELFSECTID_STRTAB-ELFSECTID_START] = extraSectionIndex++;
2090            innerBinGen->addRegion(ElfRegion64::symtabSection());
2091            innerBinSectionTable[ELFSECTID_SYMTAB-ELFSECTID_START] = extraSectionIndex++;
2092            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".shstrtab",
2093                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
2094            innerBinSectionTable[ELFSECTID_SHSTRTAB-ELFSECTID_START] = extraSectionIndex++;
2095        }
2096       
2097        if (kernelsNum != 0)
2098            putInnerSymbols(*innerBinGen, input, tempDatas, innerBinSectionTable,
2099                        extraSectionIndex, symbolNamePool, dataSymbolsNum);
2100       
2101        for (const BinSection& section: input->innerExtraSections)
2102            innerBinGen->addRegion(ElfRegion64(section, innerBinSectionTable,
2103                         AMDCL2SECTID_MAX, extraSectionIndex));
2104        // section table
2105        innerBinGen->addRegion(ElfRegion64::sectionHeaderTable());
2106        /// program headers
2107        if (kernelsNum != 0)
2108        {
2109            cxuint textSectionReg = (is16_3Ver) ? 4 : 1;
2110            if (hasRWData && input->bssSize!=0)
2111            {
2112                innerBinGen->addProgramHeader({ PT_LOOS+1, PF_W|PF_R, textSectionReg, 2,
2113                                true, 0, 0, 0 });
2114                textSectionReg += 2;
2115            }
2116            else if (hasRWData)
2117            {
2118                innerBinGen->addProgramHeader({ PT_LOOS+1, PF_W|PF_R, textSectionReg, 1,
2119                                true, 0, 0, 0 });
2120                textSectionReg++;
2121            }
2122            else if (input->bssSize!=0)
2123            {
2124                innerBinGen->addProgramHeader({ PT_LOOS+1, PF_W|PF_R, textSectionReg, 1,
2125                                true, 0, 0, 0 });
2126                textSectionReg++;
2127            }
2128            if (hasGlobalData)
2129            {   // textSectionReg - now is global data section
2130                innerBinGen->addProgramHeader({ PT_LOOS+2, PF_W|PF_R, textSectionReg, 1,
2131                        true, 0, Elf64Types::nobase
2132                        /*(hasRWData || input->bssSize!=0) ? -0xe8ULL+ : 0*/, 0 });
2133                textSectionReg++; // now is text section index
2134            }
2135            uint32_t phFlags = (is16_3Ver) ? (PF_X|PF_R) : (PF_R|PF_W);
2136            innerBinGen->addProgramHeader({ PT_LOOS+3, phFlags, textSectionReg, 1,
2137                    true, 0, Elf64Types::nobase, 0 });
2138        }
2139    }
2140   
2141    CL2MainTextGen mainTextGen(input, tempDatas, innerBinGen.get());
2142    if (kernelsNum != 0 || newBinaries)
2143        elfBinGen.addRegion(ElfRegion64(mainTextGen.size(), &mainTextGen, 1, ".text",
2144                    SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR));
2145   
2146    for (const BinSection& section: input->extraSections)
2147            elfBinGen.addRegion(ElfRegion64(section, mainBuiltinSectionTable,
2148                         ELFSECTID_STD_MAX, mainExtraSectionIndex));
2149    elfBinGen.addRegion(ElfRegion64::sectionHeaderTable());
2150   
2151    const uint64_t binarySize = elfBinGen.countSize();
2152    /****
2153     * prepare for write binary to output
2154     ****/
2155    std::unique_ptr<std::ostream> outStreamHolder;
2156    std::ostream* os = nullptr;
2157    if (aPtr != nullptr)
2158    {
2159        aPtr->resize(binarySize);
2160        outStreamHolder.reset(
2161            new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
2162        os = outStreamHolder.get();
2163    }
2164    else if (vPtr != nullptr)
2165    {
2166        vPtr->resize(binarySize);
2167        outStreamHolder.reset(new VectorOStream(*vPtr));
2168        os = outStreamHolder.get();
2169    }
2170    else // from argument
2171        os = osPtr;
2172   
2173    const std::ios::iostate oldExceptions = os->exceptions();
2174    FastOutputBuffer fob(256, *os);
2175    try
2176    {
2177        os->exceptions(std::ios::failbit | std::ios::badbit);
2178        elfBinGen.generate(fob);
2179    }
2180    catch(...)
2181    {
2182        os->exceptions(oldExceptions);
2183        throw;
2184    }
2185    os->exceptions(oldExceptions);
2186    assert(fob.getWritten() == binarySize);
2187}
2188
2189void AmdCL2GPUBinGenerator::generate(Array<cxbyte>& array) const
2190{
2191    generateInternal(nullptr, nullptr, &array);
2192}
2193
2194void AmdCL2GPUBinGenerator::generate(std::ostream& os) const
2195{
2196    generateInternal(&os, nullptr, nullptr);
2197}
2198
2199void AmdCL2GPUBinGenerator::generate(std::vector<char>& vector) const
2200{
2201    generateInternal(nullptr, &vector, nullptr);
2202}
Note: See TracBrowser for help on using the repository browser.