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

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

CLRadeonExtender: Remove obsolete data from AmdCL2BinGen. Change ElfRegion::noteSection definition.
ROCmBinaries: add dynamics and notes.

File size: 86.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
1612static const cxbyte noteDescType1[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
1613static const cxbyte noteDescType2[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 };
1614static const cxbyte noteDescType3[30] =
1615{ 4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1616  'A', 'M', 'D', 0, 'A', 'M', 'D', 'G', 'P', 'U', 0, 0, 0, 0  };
1617static const cxbyte noteDescType4[8] =
1618{ 0xf0, 0x83, 0x17, 0xfb, 0xfc, 0x7f, 0x00, 0x00 };
1619static const cxbyte noteDescType4_16_3[0x29] =
1620{ 0x19, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'A', 'M', 'D', ' ', 'H', 'S', 'A', ' ',
1621  'R', 'u', 'n', 't', 'i', 'm', 'e', ' ',
1622  'F', 'i', 'n', 'a', 'l', 'i', 'z', 'e', 'r', 0, 0, 0, 0  };
1623static const cxbyte noteDescType5[25] =
1624{ 0x16, 0, '-', 'h', 's', 'a', '_', 'c', 'a', 'l', 'l', '_',
1625    'c', 'o', 'n', 'v', 'e', 'n', 't', 'i', 'o', 'n', '=', 0, 0 };
1626static const cxbyte noteDescType5_16_3[26] =
1627{ 0x16, 0, '-', 'h', 's', 'a', '_', 'c', 'a', 'l', 'l', '_',
1628    'c', 'o', 'n', 'v', 'e', 'n', 't', 'i', 'o', 'n', '=', '0', 0, 0 };
1629static const cxbyte noteDescType5_gpupro[26] =
1630{ 0x16, 0, '-', 'h', 's', 'a', '_', 'c', 'a', 'l', 'l', '_',
1631    'c', 'o', 'n', 'v', 'e', 'n', 't', 'i', 'o', 'n', '=', '0', 0, 't' };
1632
1633struct AMDGPUArchValues
1634{
1635    uint32_t major;
1636    uint32_t minor;
1637    uint32_t stepping;
1638};
1639
1640/* TODO: add gpu values tables for various driver version */
1641static const AMDGPUArchValues amdGpuArchValuesTbl[] =
1642{
1643    { 0, 0, 0 }, // GPUDeviceType::CAPE_VERDE
1644    { 0, 0, 0 }, // GPUDeviceType::PITCAIRN
1645    { 0, 0, 0 }, // GPUDeviceType::TAHITI
1646    { 0, 0, 0 }, // GPUDeviceType::OLAND
1647    { 7, 0, 0 }, // GPUDeviceType::BONAIRE
1648    { 7, 0, 0 }, // GPUDeviceType::SPECTRE
1649    { 7, 0, 0 }, // GPUDeviceType::SPOOKY
1650    { 7, 0, 0 }, // GPUDeviceType::KALINDI
1651    { 0, 0, 0 }, // GPUDeviceType::HAINAN
1652    { 7, 0, 1 }, // GPUDeviceType::HAWAII
1653    { 8, 0, 0 }, // GPUDeviceType::ICELAND
1654    { 8, 0, 0 }, // GPUDeviceType::TONGA
1655    { 7, 0, 0 }, // GPUDeviceType::MULLINS
1656    { 8, 0, 4 }, // GPUDeviceType::FIJI
1657    { 8, 0, 1 }, // GPUDeviceType::CARRIZO
1658    { 0, 0, 0 }, // GPUDeviceType::DUMMY
1659    { 0, 0, 0 }, // GPUDeviceType::GOOSE
1660    { 0, 0, 0 }, // GPUDeviceType::HORSE
1661    { 8, 1, 0 }, // GPUDeviceType::STONEY
1662    { 8, 0, 4 }, // GPUDeviceType::ELLESMERE
1663    { 8, 0, 4 } // GPUDeviceType::BAFFIN
1664};
1665
1666static CString constructName(size_t prefixSize, const char* prefix, const CString& name,
1667                 size_t suffixSize, const char* suffix)
1668{
1669    const size_t nameLen = name.size();
1670    CString out(prefixSize + suffixSize + nameLen);
1671    char* outPtr = out.begin();
1672    std::copy(prefix, prefix+prefixSize, outPtr);
1673    std::copy(name.begin(), name.begin()+nameLen, outPtr+prefixSize);
1674    std::copy(suffix, suffix+suffixSize, outPtr+prefixSize+nameLen);
1675    return out;
1676}
1677
1678static void putInnerSymbols(ElfBinaryGen64& innerBinGen, const AmdCL2Input* input,
1679        const Array<TempAmdCL2KernelData>& tempDatas, const uint16_t* builtinSectionTable,
1680        cxuint extraSeciontIndex, std::vector<CString>& stringPool, size_t dataSymbolsNum)
1681{
1682    const size_t samplersNum = (input->samplerConfig) ? input->samplers.size() :
1683                (input->samplerInitSize>>3);
1684    // put kernel symbols
1685    std::vector<bool> samplerMask(samplersNum);
1686    size_t samplerOffset = input->globalDataSize - samplersNum;
1687    size_t codePos = 0;
1688    const uint16_t textSectId = builtinSectionTable[ELFSECTID_TEXT-ELFSECTID_START];
1689    const uint16_t globalSectId = builtinSectionTable[ELFSECTID_RODATA-ELFSECTID_START];
1690    const uint16_t atomicSectId = builtinSectionTable[
1691                ELFSECTID_DATA-ELFSECTID_START];
1692    const uint16_t sampInitSectId = builtinSectionTable[
1693                AMDCL2SECTID_SAMPLERINIT-ELFSECTID_START];
1694    const uint16_t bssSectId = builtinSectionTable[ELFSECTID_BSS-ELFSECTID_START];
1695    stringPool.resize(input->kernels.size() + samplersNum + dataSymbolsNum);
1696    size_t nameIdx = 0;
1697   
1698    /* put data symbols */
1699    for (const BinSymbol& symbol: input->innerExtraSymbols)
1700        if (symbol.sectionId==ELFSECTID_RODATA || symbol.sectionId==ELFSECTID_DATA ||
1701                   symbol.sectionId==ELFSECTID_BSS)
1702        {
1703            stringPool[nameIdx] = constructName(12, "&input_bc::&", symbol.name,
1704                        0, nullptr);
1705            innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(),
1706                  convertSectionId(symbol.sectionId, builtinSectionTable, AMDCL2SECTID_MAX,
1707                           extraSeciontIndex),
1708                  ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), 0, false, symbol.value, 
1709                  symbol.size));
1710            nameIdx++;
1711        }
1712    for (size_t i = 0; i < input->kernels.size(); i++)
1713    {   // first, we put sampler objects
1714        const AmdCL2KernelInput& kernel = input->kernels[i];
1715        const TempAmdCL2KernelData& tempData = tempDatas[i];
1716        if ((codePos & 255) != 0)
1717            codePos += 256-(codePos&255);
1718       
1719        if (kernel.useConfig)
1720            for (cxuint samp: kernel.config.samplers)
1721            {
1722                if (samplerMask[samp])
1723                    continue; // if added to symbol table
1724                const uint64_t value = !input->samplerOffsets.empty() ?
1725                        input->samplerOffsets[samp] : samplerOffset + samp*8;
1726                char sampName[64];
1727                memcpy(sampName, "&input_bc::&_.Samp", 18);
1728                itocstrCStyle<cxuint>(samp, sampName+18, 64-18);
1729                stringPool[nameIdx] = sampName;
1730                innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(), globalSectId,
1731                          ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), 0, false, value, 8));
1732                nameIdx++;
1733                samplerMask[samp] = true;
1734            }
1735        // put kernel symbol
1736        stringPool[nameIdx] = constructName(10, "&__OpenCL_", kernel.kernelName,
1737                        7, "_kernel");
1738       
1739        innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(), textSectId,
1740                  ELF64_ST_INFO(STB_GLOBAL, 10), 0, false, codePos, 
1741                  kernel.codeSize + tempData.setupSize));
1742        nameIdx++;
1743        codePos += kernel.codeSize + tempData.setupSize;
1744    }
1745   
1746    for (size_t i = 0; i < samplersNum; i++)
1747        if (!samplerMask[i])
1748        {
1749            const uint64_t value = !input->samplerOffsets.empty() ?
1750                    input->samplerOffsets[i] : samplerOffset + i*8;
1751            char sampName[64];
1752            memcpy(sampName, "&input_bc::&_.Samp", 18);
1753            itocstrCStyle<cxuint>(i, sampName+18, 64-18);
1754            stringPool[nameIdx] = sampName;
1755            innerBinGen.addSymbol(ElfSymbol64(stringPool[nameIdx].c_str(), globalSectId,
1756                      ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), 0, false, value, 8));
1757            nameIdx++;
1758            samplerMask[i] = true;
1759        }
1760   
1761    if (input->rwDataSize!=0 && input->rwData!=nullptr)
1762        innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsadata_global_agent",
1763              atomicSectId, ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1764    if (input->bssSize!=0)
1765        innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsabss_global_agent",
1766              bssSectId, ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1767    if (input->globalDataSize!=0 && input->globalData!=nullptr)
1768        innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsadata_readonly_agent",
1769              globalSectId, ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1770    innerBinGen.addSymbol(ElfSymbol64("__hsa_section.hsatext", textSectId,
1771              ELF64_ST_INFO(STB_LOCAL, STT_SECTION), 0, false, 0, 0));
1772   
1773    for (size_t i = 0; i < samplersNum; i++)
1774        innerBinGen.addSymbol(ElfSymbol64("", sampInitSectId, ELF64_ST_INFO(STB_LOCAL, 12),
1775                      0, false, i*8, 0));
1776    /// add extra inner symbols
1777    for (const BinSymbol& extraSym: input->innerExtraSymbols)
1778        innerBinGen.addSymbol(ElfSymbol64(extraSym, builtinSectionTable, AMDCL2SECTID_MAX,
1779                                  extraSeciontIndex));
1780}
1781
1782/// main routine to generate OpenCL 2.0 binary
1783void AmdCL2GPUBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
1784             Array<cxbyte>* aPtr) const
1785{
1786    const size_t kernelsNum = input->kernels.size();
1787    const bool newBinaries = input->driverVersion >= 191205;
1788    const bool hasSamplers = !input->samplerOffsets.empty() ||
1789                (!input->samplerConfig && input->samplerInitSize!=0 &&
1790                    input->samplerInit!=nullptr) ||
1791                (input->samplerConfig && !input->samplers.empty());
1792    const bool hasGlobalData = input->globalDataSize!=0 && input->globalData!=nullptr;
1793    const bool hasRWData = input->rwDataSize!=0 && input->rwData!=nullptr;
1794   
1795    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(input->deviceType);
1796    if (arch == GPUArchitecture::GCN1_0)
1797        throw Exception("OpenCL 2.0 supported only for GCN1.1 or later");
1798   
1799    AMDGPUArchValues amdGpuArchValues = amdGpuArchValuesTbl[cxuint(input->deviceType)];
1800    if (input->archMinor!=UINT32_MAX)
1801        amdGpuArchValues.minor = input->archMinor;
1802    if (input->archStepping!=UINT32_MAX)
1803        amdGpuArchValues.stepping = input->archStepping;
1804   
1805    if ((hasGlobalData || hasRWData || hasSamplers) && !newBinaries)
1806        throw Exception("Old driver binaries doesn't support "
1807                        "global/atomic data or samplers");
1808   
1809    if (newBinaries)
1810    {
1811        if (!hasGlobalData && hasSamplers)
1812            throw Exception("Global data must be defined if samplers present");
1813        // check sampler offset range
1814        for (size_t sampOffset: input->samplerOffsets)
1815            if (sampOffset+8 > input->globalDataSize)
1816                throw Exception("Sampler offset outside global data");
1817    }
1818    /* check samplers */
1819    const cxuint samplersNum = (input->samplerConfig) ? input->samplers.size() :
1820                (input->samplerInitSize>>3);
1821    if (!input->samplerOffsets.empty() && input->samplerOffsets.size() != samplersNum)
1822        throw Exception("SamplerOffset number doesn't match to samplers number");
1823   
1824    for (size_t sampOffset: input->samplerOffsets)
1825        if ((sampOffset&7) != 0 && sampOffset >= input->globalDataSize)
1826            throw Exception("Wrong sampler offset (out of range of unaligned)");
1827   
1828    const bool gpuProDriver = (input->driverVersion == 203603 ||
1829            input->driverVersion == 207903);
1830    /* determine correct flags for device type */
1831    const uint32_t* deviceCodeTable;
1832    if (input->driverVersion < 191205)
1833        deviceCodeTable = gpuDeviceCodeTable15_7;
1834    else if (input->driverVersion < 200406)
1835        deviceCodeTable = gpuDeviceCodeTable;
1836    else if (input->driverVersion < 203603)
1837        deviceCodeTable = gpuDeviceCodeTable16_3;
1838    else // AMD GPUPRO driver and later
1839        deviceCodeTable = gpuDeviceCodeTableGPUPRO;
1840    // if GPU type is not supported by driver version
1841    if (deviceCodeTable[cxuint(input->deviceType)] == UINT_MAX)
1842        throw Exception("Unsupported GPU device type by driver version");
1843   
1844    ElfBinaryGen64 elfBinGen({ 0, 0, ELFOSABI_SYSV, 0, ET_EXEC, 0xaf5b, EV_CURRENT,
1845                UINT_MAX, 0, deviceCodeTable[cxuint(input->deviceType)] });
1846   
1847    CString aclVersion = input->aclVersion;
1848    if (aclVersion.empty())
1849    {
1850        if (newBinaries)
1851            aclVersion = "AMD-COMP-LIB-v0.8 (0.0.SC_BUILD_NUMBER)";
1852        else // old binaries
1853            aclVersion = "AMD-COMP-LIB-v0.8 (0.0.326)";
1854    }
1855   
1856    Array<TempAmdCL2KernelData> tempDatas(kernelsNum);
1857    prepareKernelTempData(input, tempDatas);
1858   
1859    const size_t dataSymbolsNum = std::count_if(input->innerExtraSymbols.begin(),
1860        input->innerExtraSymbols.end(), [](const BinSymbol& symbol)
1861        { return symbol.sectionId==ELFSECTID_RODATA || symbol.sectionId==ELFSECTID_DATA ||
1862                   symbol.sectionId==ELFSECTID_BSS; });
1863   
1864    cxuint mainExtraSectionIndex = 6 + (kernelsNum != 0 || newBinaries);
1865    CL2MainStrTabGen mainStrTabGen(input);
1866    CL2MainSymTabGen mainSymTabGen(input, tempDatas, aclVersion, mainExtraSectionIndex);
1867    CL2MainCommentGen mainCommentGen(input, aclVersion);
1868    CL2MainRodataGen mainRodataGen(input, tempDatas);
1869    CL2InnerTextGen innerTextGen(input, tempDatas);
1870    CL2InnerGlobalDataGen innerGDataGen(input);
1871    CL2InnerSamplerInitGen innerSamplerInitGen(input);
1872    CL2InnerTextRelsGen innerTextRelsGen(input, tempDatas, dataSymbolsNum);
1873    CL2InnerGlobalDataRelsGen innerGDataRels(input, dataSymbolsNum);
1874   
1875    // main section of main binary
1876    elfBinGen.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".shstrtab",
1877                    SHT_STRTAB, SHF_STRINGS));
1878    elfBinGen.addRegion(ElfRegion64(mainStrTabGen.size(), &mainStrTabGen, 1, ".strtab",
1879                    SHT_STRTAB, SHF_STRINGS));
1880    elfBinGen.addRegion(ElfRegion64(mainSymTabGen.size(), &mainSymTabGen, 8, ".symtab",
1881                    SHT_SYMTAB, 0));
1882    elfBinGen.addRegion(ElfRegion64(input->compileOptions.size()+aclVersion.size(),
1883                    &mainCommentGen, 1, ".comment", SHT_PROGBITS, 0));
1884    if (kernelsNum != 0)
1885        elfBinGen.addRegion(ElfRegion64(mainRodataGen.size(), &mainRodataGen, 1, ".rodata",
1886                    SHT_PROGBITS, SHF_ALLOC));
1887   
1888    std::unique_ptr<ElfBinaryGen64> innerBinGen;
1889    std::vector<CString> symbolNamePool;
1890    std::unique_ptr<cxbyte[]> noteBuf;
1891    if (newBinaries)
1892    {   // new binaries - .text holds inner ELF binaries
1893        bool is16_3Ver = (input->driverVersion>=200406);
1894        uint16_t innerBinSectionTable[innerBinSectonTableLen];
1895        cxuint extraSectionIndex = 1;
1896        /* check kernel text relocations */
1897        for (const AmdCL2KernelInput& kernel: input->kernels)
1898            for (const AmdCL2RelInput& rel: kernel.relocations)
1899                if (rel.offset >= kernel.codeSize)
1900                    throw Exception("Kernel text relocation offset outside kernel code");
1901       
1902        std::fill(innerBinSectionTable,
1903                  innerBinSectionTable+innerBinSectonTableLen, SHN_UNDEF);
1904       
1905        cxuint symtabId, globalDataId, textId;
1906        if (!is16_3Ver)
1907        {
1908            symtabId = 4 + (hasSamplers?2:0) /* samplerinit&rela.global */ +
1909                    (hasRWData) + (hasGlobalData) +
1910                    (input->bssSize!=0) +
1911                    (hasRWData || hasGlobalData || input->bssSize!=0) /* rela.hsatext */;
1912            globalDataId = 1 + (hasRWData) + (input->bssSize!=0);
1913            textId = 1 + (hasRWData) + (hasGlobalData) + (input->bssSize!=0);
1914        }
1915        else
1916        {
1917            textId = 4 + (hasRWData) + (hasGlobalData) + (input->bssSize!=0);
1918            symtabId = 5 + (hasRWData) + (hasGlobalData) + (input->bssSize!=0);
1919            globalDataId = 4 + (hasRWData) + (input->bssSize!=0);
1920        }
1921        /* in innerbin we do not add null symbol, we count address for program headers
1922         * and section from first section */
1923        innerBinGen.reset(new ElfBinaryGen64({ 0, 0, 0x40, 0, ET_REL, 0xe0, EV_CURRENT,
1924                        UINT_MAX, 0, 0 }, (input->driverVersion>=200406), true, true, 
1925                        /* globaldata sectionid: for 200406 - 4, for older - 1 */
1926                        (!is16_3Ver) ? 1 : 4));
1927        innerBinGen->addRegion(ElfRegion64::programHeaderTable());
1928       
1929        if (is16_3Ver)
1930        {   /* first is shstrab and strtab */
1931            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8, ".shstrtab",
1932                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
1933            innerBinSectionTable[ELFSECTID_SHSTRTAB-ELFSECTID_START] = extraSectionIndex++;
1934            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8, ".strtab",
1935                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
1936            innerBinSectionTable[ELFSECTID_STRTAB-ELFSECTID_START] = extraSectionIndex++;
1937           
1938            // set AMDGPU type
1939            /*
1940             * AMD - 1 - 00000001 00000000
1941             * AMD - 2 - 00000001 00000000 00010101
1942             * AMD - 3 - size=0x1a, 00070004 major minor stepping AMD\0 AMDGPU\0
1943             * AMD - 4 - size=0x29 00000019 00000001 00000000
1944             *      "AMD HSA Runtime Finalizer" 00000000
1945             * AMD - 5 - size=0x19 \x16\000-hsa_call_convention=\0\0
1946             */
1947            innerBinGen->addNote(ElfNote("AMD", sizeof noteDescType1, noteDescType1, 1U));
1948            innerBinGen->addNote(ElfNote("AMD", sizeof noteDescType2, noteDescType2, 2U));
1949            noteBuf.reset(new cxbyte[0x1a]);
1950            ::memcpy(noteBuf.get(), noteDescType3, 0x1a);
1951            SULEV(*(uint32_t*)(noteBuf.get()+4), amdGpuArchValues.major);
1952            SULEV(*(uint32_t*)(noteBuf.get()+8), amdGpuArchValues.minor);
1953            SULEV(*(uint32_t*)(noteBuf.get()+12), amdGpuArchValues.stepping);
1954            innerBinGen->addNote(ElfNote("AMD", 0x1a, noteBuf.get(), 3U));
1955            innerBinGen->addNote(ElfNote("AMD",
1956                         sizeof noteDescType4_16_3, noteDescType4_16_3, 4U));
1957            if (!gpuProDriver)
1958                innerBinGen->addNote(ElfNote("AMD",
1959                             sizeof noteDescType5_16_3, noteDescType5_16_3, 5U));
1960            else
1961                innerBinGen->addNote(ElfNote("AMD",
1962                             sizeof noteDescType5_gpupro, noteDescType5_gpupro, 5U));
1963           
1964            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
1965                             ".note", SHT_NOTE, 0));
1966            innerBinSectionTable[AMDCL2SECTID_NOTE-ELFSECTID_START] = extraSectionIndex++;
1967        }
1968        if (hasRWData)
1969        {   // rw data section
1970            innerBinGen->addRegion(ElfRegion64(input->rwDataSize, input->rwData,
1971                      8, ".hsadata_global_agent", SHT_PROGBITS, 0x900003, 0, 0,
1972                      Elf64Types::nobase));
1973            innerBinSectionTable[ELFSECTID_DATA-ELFSECTID_START] =
1974                    extraSectionIndex++;
1975        }
1976        if (input->bssSize!=0)
1977        {
1978            innerBinGen->addRegion(ElfRegion64(input->bssSize, (const cxbyte*)nullptr,
1979                      input->bssAlignment!=0 ? input->bssAlignment : 8,
1980                      ".hsabss_global_agent", SHT_NOBITS, 0x900003,
1981                      0, 0, Elf64Types::nobase, 0, true));
1982            innerBinSectionTable[ELFSECTID_BSS-ELFSECTID_START] = extraSectionIndex++;
1983        }
1984        if (hasGlobalData)
1985        {// global data section
1986            innerBinGen->addRegion(ElfRegion64(innerGDataGen.size(), &innerGDataGen,
1987                      8, ".hsadata_readonly_agent", SHT_PROGBITS, 0xa00003, 0, 0,
1988                      Elf64Types::nobase));
1989            innerBinSectionTable[ELFSECTID_RODATA-ELFSECTID_START] = extraSectionIndex++;
1990        }
1991        if (kernelsNum != 0)
1992        {
1993            innerBinGen->addRegion(ElfRegion64(innerTextGen.size(), &innerTextGen, 256,
1994                      ".hsatext", SHT_PROGBITS, 0xc00007, 0, 0, 
1995                      Elf64Types::nobase, 0));
1996            innerBinSectionTable[ELFSECTID_TEXT-ELFSECTID_START] = extraSectionIndex++;
1997        }
1998       
1999        if (is16_3Ver)
2000        {   /* new driver version */
2001            innerBinGen->addRegion(ElfRegion64::symtabSection());
2002            innerBinSectionTable[ELFSECTID_SYMTAB-ELFSECTID_START] = extraSectionIndex++;
2003        }
2004       
2005        if (hasSamplers)
2006        {
2007            innerBinGen->addRegion(ElfRegion64(input->samplerConfig ?
2008                    input->samplers.size()*8 : input->samplerInitSize,
2009                    &innerSamplerInitGen, (is16_3Ver) ? 8 : 1,
2010                    ".hsaimage_samplerinit", SHT_PROGBITS, SHF_MERGE, 0, 0, 0, 8));
2011            innerBinSectionTable[AMDCL2SECTID_SAMPLERINIT-ELFSECTID_START] =
2012                        extraSectionIndex++;
2013            innerBinGen->addRegion(ElfRegion64(innerGDataRels.size(), &innerGDataRels,
2014                    8, ".rela.hsadata_readonly_agent", SHT_RELA, 0, symtabId,
2015                    globalDataId, 0, sizeof(Elf64_Rela)));
2016            innerBinSectionTable[AMDCL2SECTID_RODATARELA-ELFSECTID_START] =
2017                        extraSectionIndex++;
2018        }
2019        size_t textRelSize = innerTextRelsGen.size();
2020        if (textRelSize!=0) // if some relocations
2021        {
2022            innerBinGen->addRegion(ElfRegion64(textRelSize, &innerTextRelsGen, 8,
2023                    ".rela.hsatext", SHT_RELA, 0, symtabId, textId,  0,
2024                    sizeof(Elf64_Rela)));
2025            innerBinSectionTable[AMDCL2SECTID_TEXTRELA-ELFSECTID_START] =
2026                    extraSectionIndex++;
2027        }
2028       
2029        if (!is16_3Ver)
2030        {   /* this order of section for 1912.05 driver version */
2031            /* AMD - 1 - 00000001 00000000
2032             * AMD - 2 - 00000001 00000000 00010101
2033             * AMD - 5 - size=0x19 \x16\000-hsa_call_convention=\0\0
2034             * AMD - 3 - size=0x1e, 00070004 major minor stepping AMD\0 AMDGPU\0 00000000
2035             * AMD - 4 - size=8 random values 0x7ffXXXXXXXX
2036             */
2037            innerBinGen->addNote(ElfNote("AMD", sizeof noteDescType1, noteDescType1, 1U));
2038            innerBinGen->addNote(ElfNote("AMD", sizeof noteDescType2, noteDescType2, 2U));
2039            innerBinGen->addNote(ElfNote("AMD", sizeof noteDescType5, noteDescType5, 5U));
2040            noteBuf.reset(new cxbyte[0x1e]);
2041            ::memcpy(noteBuf.get(), noteDescType3, 0x1e);
2042            SULEV(*(uint32_t*)(noteBuf.get()+4), amdGpuArchValues.major);
2043            SULEV(*(uint32_t*)(noteBuf.get()+8), amdGpuArchValues.minor);
2044            SULEV(*(uint32_t*)(noteBuf.get()+12), amdGpuArchValues.stepping);
2045            innerBinGen->addNote(ElfNote("AMD", 0x1e, noteBuf.get(), 3U));
2046            innerBinGen->addNote(ElfNote("AMD", sizeof noteDescType4, noteDescType4, 4U));
2047           
2048            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
2049                                   ".note", SHT_NOTE, 0));
2050           
2051            innerBinSectionTable[AMDCL2SECTID_NOTE-ELFSECTID_START] = extraSectionIndex++;
2052            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".strtab",
2053                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
2054            innerBinSectionTable[ELFSECTID_STRTAB-ELFSECTID_START] = extraSectionIndex++;
2055            innerBinGen->addRegion(ElfRegion64::symtabSection());
2056            innerBinSectionTable[ELFSECTID_SYMTAB-ELFSECTID_START] = extraSectionIndex++;
2057            innerBinGen->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".shstrtab",
2058                                  SHT_STRTAB, SHF_STRINGS, 0, 0));
2059            innerBinSectionTable[ELFSECTID_SHSTRTAB-ELFSECTID_START] = extraSectionIndex++;
2060        }
2061       
2062        if (kernelsNum != 0)
2063            putInnerSymbols(*innerBinGen, input, tempDatas, innerBinSectionTable,
2064                        extraSectionIndex, symbolNamePool, dataSymbolsNum);
2065       
2066        for (const BinSection& section: input->innerExtraSections)
2067            innerBinGen->addRegion(ElfRegion64(section, innerBinSectionTable,
2068                         AMDCL2SECTID_MAX, extraSectionIndex));
2069        // section table
2070        innerBinGen->addRegion(ElfRegion64::sectionHeaderTable());
2071        /// program headers
2072        if (kernelsNum != 0)
2073        {
2074            cxuint textSectionReg = (is16_3Ver) ? 4 : 1;
2075            if (hasRWData && input->bssSize!=0)
2076            {
2077                innerBinGen->addProgramHeader({ PT_LOOS+1, PF_W|PF_R, textSectionReg, 2,
2078                                true, 0, 0, 0 });
2079                textSectionReg += 2;
2080            }
2081            else if (hasRWData)
2082            {
2083                innerBinGen->addProgramHeader({ PT_LOOS+1, PF_W|PF_R, textSectionReg, 1,
2084                                true, 0, 0, 0 });
2085                textSectionReg++;
2086            }
2087            else if (input->bssSize!=0)
2088            {
2089                innerBinGen->addProgramHeader({ PT_LOOS+1, PF_W|PF_R, textSectionReg, 1,
2090                                true, 0, 0, 0 });
2091                textSectionReg++;
2092            }
2093            if (hasGlobalData)
2094            {   // textSectionReg - now is global data section
2095                innerBinGen->addProgramHeader({ PT_LOOS+2, PF_W|PF_R, textSectionReg, 1,
2096                        true, 0, Elf64Types::nobase
2097                        /*(hasRWData || input->bssSize!=0) ? -0xe8ULL+ : 0*/, 0 });
2098                textSectionReg++; // now is text section index
2099            }
2100            uint32_t phFlags = (is16_3Ver) ? (PF_X|PF_R) : (PF_R|PF_W);
2101            innerBinGen->addProgramHeader({ PT_LOOS+3, phFlags, textSectionReg, 1,
2102                    true, 0, Elf64Types::nobase, 0 });
2103        }
2104    }
2105   
2106    CL2MainTextGen mainTextGen(input, tempDatas, innerBinGen.get());
2107    if (kernelsNum != 0 || newBinaries)
2108        elfBinGen.addRegion(ElfRegion64(mainTextGen.size(), &mainTextGen, 1, ".text",
2109                    SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR));
2110   
2111    for (const BinSection& section: input->extraSections)
2112            elfBinGen.addRegion(ElfRegion64(section, mainBuiltinSectionTable,
2113                         ELFSECTID_STD_MAX, mainExtraSectionIndex));
2114    elfBinGen.addRegion(ElfRegion64::sectionHeaderTable());
2115   
2116    const uint64_t binarySize = elfBinGen.countSize();
2117    /****
2118     * prepare for write binary to output
2119     ****/
2120    std::unique_ptr<std::ostream> outStreamHolder;
2121    std::ostream* os = nullptr;
2122    if (aPtr != nullptr)
2123    {
2124        aPtr->resize(binarySize);
2125        outStreamHolder.reset(
2126            new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
2127        os = outStreamHolder.get();
2128    }
2129    else if (vPtr != nullptr)
2130    {
2131        vPtr->resize(binarySize);
2132        outStreamHolder.reset(new VectorOStream(*vPtr));
2133        os = outStreamHolder.get();
2134    }
2135    else // from argument
2136        os = osPtr;
2137   
2138    const std::ios::iostate oldExceptions = os->exceptions();
2139    FastOutputBuffer fob(256, *os);
2140    try
2141    {
2142        os->exceptions(std::ios::failbit | std::ios::badbit);
2143        elfBinGen.generate(fob);
2144    }
2145    catch(...)
2146    {
2147        os->exceptions(oldExceptions);
2148        throw;
2149    }
2150    os->exceptions(oldExceptions);
2151    assert(fob.getWritten() == binarySize);
2152}
2153
2154void AmdCL2GPUBinGenerator::generate(Array<cxbyte>& array) const
2155{
2156    generateInternal(nullptr, nullptr, &array);
2157}
2158
2159void AmdCL2GPUBinGenerator::generate(std::ostream& os) const
2160{
2161    generateInternal(&os, nullptr, nullptr);
2162}
2163
2164void AmdCL2GPUBinGenerator::generate(std::vector<char>& vector) const
2165{
2166    generateInternal(nullptr, &vector, nullptr);
2167}
Note: See TracBrowser for help on using the repository browser.