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

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

CLRadeonExtender: Apply Elf notes support in AmdCL2BinGen. write name with zero while storing note in elf (ElfBinGen?).
Add constructors to ElfNote?.

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