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

Last change on this file since 3712 was 3712, checked in by matszpk, 2 years ago

CLRadeonExtender: AmdCL2: Handle vectypehint and work_group_size_hint in kernel metadata. Add '.vectypehint' and '.work_group_size_hint' pseudo-ops
to AmdCL2 format handling. Add new pseudo-ops to editor's syntaxes.

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