source: CLRX/CLRadeonExtender/trunk/amdasm/GCNDisasm.cpp @ 4135

Last change on this file since 4135 was 4135, checked in by matszpk, 6 months ago

CLRadeonExtender: Asm: Move GCN encoding and decoding stuff to separate source codes.

File size: 36.2 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 <algorithm>
22#include <iostream>
23#include <cstring>
24#include <mutex>
25#include <memory>
26#include <CLRX/utils/Utilities.h>
27#include <CLRX/utils/GPUId.h>
28#include <CLRX/amdasm/Disassembler.h>
29#include <CLRX/utils/MemAccess.h>
30#include "GCNInternals.h"
31#include "GCNDisasmInternals.h"
32
33using namespace CLRX;
34
35static OnceFlag clrxGCNDisasmOnceFlag;
36static std::unique_ptr<GCNInstruction[]> gcnInstrTableByCode = nullptr;
37
38// GCN encoding space
39struct CLRX_INTERNAL GCNEncodingSpace
40{
41    cxuint offset;  // first position instrunctions list
42    cxuint instrsNum;   // instruction list
43};
44
45// put chars to buffer (helper)
46static inline void putChars(char*& buf, const char* input, size_t size)
47{
48    ::memcpy(buf, input, size);
49    buf += size;
50}
51
52// add N spaces (old style), return number
53static size_t addSpacesOld(char* bufPtr, cxuint spacesToAdd)
54{
55    for (cxuint k = spacesToAdd; k>0; k--)
56        *bufPtr++ = ' ';
57    return spacesToAdd;
58}
59
60// encoding names table
61static const char* gcnEncodingNames[GCNENC_MAXVAL+1] =
62{
63    "NONE", "SOPC", "SOPP", "SOP1", "SOP2", "SOPK", "SMRD", "VOPC", "VOP1", "VOP2",
64    "VOP3A", "VOP3B", "VINTRP", "DS", "MUBUF", "MTBUF", "MIMG", "EXP", "FLAT"
65};
66
67// table hold of GNC encoding regions in main instruction list
68// instruciton position is sum of encoding offset and instruction opcode
69static const GCNEncodingSpace gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3+2] =
70{
71    { 0, 0 },
72    { 0, 0x80 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
73    { 0x0080, 0x80 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
74    { 0x0100, 0x100 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
75    { 0x0200, 0x80 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
76    { 0x0280, 0x20 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
77    { 0x02a0, 0x40 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
78    { 0x02e0, 0x100 }, /* GCNENC_VOPC, opcode = (8bit)<<27 */
79    { 0x03e0, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
80    { 0x04e0, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
81    { 0x0520, 0x200 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
82    { 0x0520, 0x200 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
83    { 0x0720, 0x4 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
84    { 0x0724, 0x100 }, /* GCNENC_DS, opcode = (8bit)<<18 */
85    { 0x0824, 0x80 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
86    { 0x08a4, 0x8 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
87    { 0x08ac, 0x80 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
88    { 0x092c, 0x1 }, /* GCNENC_EXP, opcode = none */
89    { 0x092d, 0x80 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
90    { 0x09ad, 0x200 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 (GCN1.1) */
91    { 0x09ad, 0x200 },  /* GCNENC_VOP3B, opcode = (9bit)<<17 (GCN1.1) */
92    { 0x0bad, 0x0 },
93    { 0x0bad, 0x80 }, /* GCNENC_SOPC, opcode = (7bit)<<16 (GCN1.2) */
94    { 0x0c2d, 0x80 }, /* GCNENC_SOPP, opcode = (7bit)<<16 (GCN1.2) */
95    { 0x0cad, 0x100 }, /* GCNENC_SOP1, opcode = (8bit)<<8 (GCN1.2) */
96    { 0x0dad, 0x80 }, /* GCNENC_SOP2, opcode = (7bit)<<23 (GCN1.2) */
97    { 0x0e2d, 0x20 }, /* GCNENC_SOPK, opcode = (5bit)<<23 (GCN1.2) */
98    { 0x0e4d, 0x100 }, /* GCNENC_SMEM, opcode = (8bit)<<18 (GCN1.2) */
99    { 0x0f4d, 0x100 }, /* GCNENC_VOPC, opcode = (8bit)<<27 (GCN1.2) */
100    { 0x104d, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 (GCN1.2) */
101    { 0x114d, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 (GCN1.2) */
102    { 0x118d, 0x400 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 (GCN1.2) */
103    { 0x118d, 0x400 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 (GCN1.2) */
104    { 0x158d, 0x4 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 (GCN1.2) */
105    { 0x1591, 0x100 }, /* GCNENC_DS, opcode = (8bit)<<18 (GCN1.2) */
106    { 0x1691, 0x80 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 (GCN1.2) */
107    { 0x1711, 0x10 }, /* GCNENC_MTBUF, opcode = (4bit)<<16 (GCN1.2) */
108    { 0x1721, 0x80 }, /* GCNENC_MIMG, opcode = (7bit)<<18 (GCN1.2) */
109    { 0x17a1, 0x1 }, /* GCNENC_EXP, opcode = none (GCN1.2) */
110    { 0x17a2, 0x80 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
111    { 0x1822, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 (RXVEGA) */
112    { 0x1862, 0x400 }, /* GCNENC_VOP3B, opcode = (10bit)<<17  (RXVEGA) */
113    { 0x1c62, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 (RXVEGA) */
114    { 0x1d62, 0x80 }, /* GCNENC_FLAT_SCRATCH, opcode = (8bit)<<18 (???8bit) RXVEGA */
115    { 0x1de2, 0x80 }  /* GCNENC_FLAT_GLOBAL, opcode = (8bit)<<18 (???8bit) RXVEGA */
116};
117
118// total instruction table length
119static const size_t gcnInstrTableByCodeLength = 0x1e62;
120
121// create main instruction table
122static void initializeGCNDisassembler()
123{
124    gcnInstrTableByCode.reset(new GCNInstruction[gcnInstrTableByCodeLength]);
125    for (cxuint i = 0; i < gcnInstrTableByCodeLength; i++)
126    {
127        gcnInstrTableByCode[i].mnemonic = nullptr;
128        gcnInstrTableByCode[i].mode = GCN_STDMODE;
129        // except VOP3 decoding routines ignores encoding (we can set None for encoding)
130        gcnInstrTableByCode[i].encoding = GCNENC_NONE;
131    }
132   
133    // fill up main instruction table
134    for (cxuint i = 0; gcnInstrsTable[i].mnemonic != nullptr; i++)
135    {
136        const GCNInstruction& instr = gcnInstrsTable[i];
137        const GCNEncodingSpace& encSpace = gcnInstrTableByCodeSpaces[instr.encoding];
138        if ((instr.archMask & ARCH_GCN_1_0_1) != 0)
139        {
140            if (gcnInstrTableByCode[encSpace.offset + instr.code].mnemonic == nullptr)
141                gcnInstrTableByCode[encSpace.offset + instr.code] = instr;
142            else if((instr.archMask & ARCH_RX2X0) != 0)
143            {
144                /* otherwise we for GCN1.1 */
145                const GCNEncodingSpace& encSpace2 =
146                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
147                gcnInstrTableByCode[encSpace2.offset + instr.code] = instr;
148            }
149            // otherwise we ignore this entry
150        }
151        if ((instr.archMask & ARCH_GCN_1_2_4) != 0)
152        {
153            // for GCN 1.2/1.4
154            const GCNEncodingSpace& encSpace3 = gcnInstrTableByCodeSpaces[
155                        GCNENC_MAXVAL+3+instr.encoding];
156            if (gcnInstrTableByCode[encSpace3.offset + instr.code].mnemonic == nullptr)
157                gcnInstrTableByCode[encSpace3.offset + instr.code] = instr;
158            else if((instr.archMask & ARCH_RXVEGA) != 0 &&
159                (instr.encoding == GCNENC_VOP2 || instr.encoding == GCNENC_VOP1 ||
160                instr.encoding == GCNENC_VOP3A || instr.encoding == GCNENC_VOP3B))
161            {
162                /* otherwise we for GCN1.4 */
163                const bool encNoVOP2 = instr.encoding != GCNENC_VOP2;
164                const bool encVOP1 = instr.encoding == GCNENC_VOP1;
165                // choose FLAT_GLOBAL or FLAT_SCRATCH space
166                const GCNEncodingSpace& encSpace4 =
167                    gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 + encNoVOP2 + encVOP1];
168                gcnInstrTableByCode[encSpace4.offset + instr.code] = instr;
169            }
170            else if((instr.archMask & ARCH_RXVEGA) != 0 &&
171                instr.encoding == GCNENC_FLAT && (instr.mode & GCN_FLAT_MODEMASK) != 0)
172            {
173                /* FLAT SCRATCH and GLOBAL instructions */
174                const cxuint encFlatMode = (instr.mode & GCN_FLAT_MODEMASK)-1;
175                const GCNEncodingSpace& encSpace4 =
176                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 + encFlatMode];
177                gcnInstrTableByCode[encSpace4.offset + instr.code] = instr;
178            }
179            // otherwise we ignore this entry
180        }
181    }
182}
183
184GCNDisassembler::GCNDisassembler(Disassembler& disassembler)
185        : ISADisassembler(disassembler), instrOutOfCode(false)
186{
187    callOnce(clrxGCNDisasmOnceFlag, initializeGCNDisassembler);
188}
189
190GCNDisassembler::~GCNDisassembler()
191{ }
192
193// gcn encoding sizes table: true - if 8 byte encoding, false - 4 byte encoding
194// for GCN1.0/1.1
195static const bool gcnSize11Table[16] =
196{
197    false, // GCNENC_SMRD, // 0000
198    false, // GCNENC_SMRD, // 0001
199    false, // GCNENC_VINTRP, // 0010
200    false, // GCNENC_NONE, // 0011 - illegal
201    true,  // GCNENC_VOP3A, // 0100
202    false, // GCNENC_NONE, // 0101 - illegal
203    true,  // GCNENC_DS,   // 0110
204    true,  // GCNENC_FLAT, // 0111
205    true,  // GCNENC_MUBUF, // 1000
206    false, // GCNENC_NONE,  // 1001 - illegal
207    true,  // GCNENC_MTBUF, // 1010
208    false, // GCNENC_NONE,  // 1011 - illegal
209    true,  // GCNENC_MIMG,  // 1100
210    false, // GCNENC_NONE,  // 1101 - illegal
211    true,  // GCNENC_EXP,   // 1110
212    false // GCNENC_NONE   // 1111 - illegal
213};
214
215// for GCN1.2/1.4
216static const bool gcnSize12Table[16] =
217{
218    true,  // GCNENC_SMEM, // 0000
219    true,  // GCNENC_EXP, // 0001
220    false, // GCNENC_NONE, // 0010 - illegal
221    false, // GCNENC_NONE, // 0011 - illegal
222    true,  // GCNENC_VOP3A, // 0100
223    false, // GCNENC_VINTRP, // 0101
224    true,  // GCNENC_DS,   // 0110
225    true,  // GCNENC_FLAT, // 0111
226    true,  // GCNENC_MUBUF, // 1000
227    false, // GCNENC_NONE,  // 1001 - illegal
228    true,  // GCNENC_MTBUF, // 1010
229    false, // GCNENC_NONE,  // 1011 - illegal
230    true,  // GCNENC_MIMG,  // 1100
231    false, // GCNENC_NONE,  // 1101 - illegal
232    false, // GCNENC_NONE,  // 1110 - illegal
233    false // GCNENC_NONE   // 1111 - illegal
234};
235
236void GCNDisassembler::analyzeBeforeDisassemble()
237{
238    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
239    const size_t codeWordsNum = (inputSize>>2);
240
241    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
242                disassembler.getDeviceType());
243    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
244    const bool isGCN12 = (arch >= GPUArchitecture::GCN1_2);
245    const bool isGCN14 = (arch == GPUArchitecture::GCN1_4);
246    size_t pos;
247    for (pos = 0; pos < codeWordsNum; pos++)
248    {
249        /* scan all instructions and get jump addresses */
250        const uint32_t insnCode = ULEV(codeWords[pos]);
251        if ((insnCode & 0x80000000U) != 0)
252        {
253            if ((insnCode & 0x40000000U) == 0)
254            {
255                // SOP???
256                if  ((insnCode & 0x30000000U) == 0x30000000U)
257                {
258                    // SOP1/SOPK/SOPC/SOPP
259                    const uint32_t encPart = (insnCode & 0x0f800000U);
260                    if (encPart == 0x0e800000U)
261                    {
262                        // SOP1
263                        if ((insnCode&0xff) == 0xff) // literal
264                            pos++;
265                    }
266                    else if (encPart == 0x0f000000U)
267                    {
268                        // SOPC
269                        if ((insnCode&0xff) == 0xff ||
270                            (insnCode&0xff00) == 0xff00) // literal
271                            pos++;
272                    }
273                    else if (encPart == 0x0f800000U)
274                    {
275                        // SOPP
276                        const cxuint opcode = (insnCode>>16)&0x7f;
277                        if (opcode == 2 || (opcode >= 4 && opcode <= 9) ||
278                            // GCN1.1 and GCN1.2 opcodes
279                            ((isGCN11 || isGCN12) &&
280                                    (opcode >= 23 && opcode <= 26))) // if jump
281                            labels.push_back(startOffset +
282                                    ((pos+int16_t(insnCode&0xffff)+1)<<2));
283                    }
284                    else
285                    {
286                        // SOPK
287                        const cxuint opcode = (insnCode>>23)&0x1f;
288                        if ((!isGCN12 && opcode == 17) ||
289                            (isGCN12 && opcode == 16) || // if branch fork
290                            (isGCN14 && opcode == 21)) // if s_call_b64
291                            labels.push_back(startOffset +
292                                    ((pos+int16_t(insnCode&0xffff)+1)<<2));
293                        else if ((!isGCN12 && opcode == 21) ||
294                            (isGCN12 && opcode == 20))
295                            pos++; // additional literal
296                    }
297                }
298                else
299                {
300                    // SOP2
301                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
302                        pos++;  // literal
303                }
304            }
305            else
306            {
307                // SMRD and others
308                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
309                if ((!isGCN12 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
310                    (isGCN12 && gcnSize12Table[encPart]))
311                    pos++;
312            }
313        }
314        else
315        {
316            // some vector instructions
317            if ((insnCode & 0x7e000000U) == 0x7c000000U)
318            {
319                // VOPC
320                if ((insnCode&0x1ff) == 0xff || // literal
321                    // SDWA, DDP
322                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
323                    pos++;
324            }
325            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
326            {
327                // VOP1
328                if ((insnCode&0x1ff) == 0xff || // literal
329                    // SDWA, DDP
330                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
331                    pos++;
332            }
333            else
334            {
335                // VOP2
336                const cxuint opcode = (insnCode >> 25)&0x3f;
337                if ((!isGCN12 && (opcode == 32 || opcode == 33)) ||
338                    (isGCN12 && (opcode == 23 || opcode == 24 ||
339                    opcode == 36 || opcode == 37))) // V_MADMK and V_MADAK
340                    pos++;  // inline 32-bit constant
341                else if ((insnCode&0x1ff) == 0xff || // literal
342                    // SDWA, DDP
343                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
344                    pos++;  // literal
345            }
346        }
347    }
348   
349    instrOutOfCode = (pos != codeWordsNum);
350}
351
352static const cxbyte gcnEncoding11Table[16] =
353{
354    GCNENC_SMRD, // 0000
355    GCNENC_SMRD, // 0001
356    GCNENC_VINTRP, // 0010
357    GCNENC_NONE, // 0011 - illegal
358    GCNENC_VOP3A, // 0100
359    GCNENC_NONE, // 0101 - illegal
360    GCNENC_DS,   // 0110
361    GCNENC_FLAT, // 0111
362    GCNENC_MUBUF, // 1000
363    GCNENC_NONE,  // 1001 - illegal
364    GCNENC_MTBUF, // 1010
365    GCNENC_NONE,  // 1011 - illegal
366    GCNENC_MIMG,  // 1100
367    GCNENC_NONE,  // 1101 - illegal
368    GCNENC_EXP,   // 1110
369    GCNENC_NONE   // 1111 - illegal
370};
371
372static const cxbyte gcnEncoding12Table[16] =
373{
374    GCNENC_SMEM, // 0000
375    GCNENC_EXP, // 0001
376    GCNENC_NONE, // 0010 - illegal
377    GCNENC_NONE, // 0011 - illegal
378    GCNENC_VOP3A, // 0100
379    GCNENC_VINTRP, // 0101
380    GCNENC_DS,   // 0110
381    GCNENC_FLAT, // 0111
382    GCNENC_MUBUF, // 1000
383    GCNENC_NONE,  // 1001 - illegal
384    GCNENC_MTBUF, // 1010
385    GCNENC_NONE,  // 1011 - illegal
386    GCNENC_MIMG,  // 1100
387    GCNENC_NONE,  // 1101 - illegal
388    GCNENC_NONE,  // 1110 - illegal
389    GCNENC_NONE   // 1111 - illegal
390};
391
392
393struct CLRX_INTERNAL GCNEncodingOpcodeBits
394{
395    cxbyte bitPos;
396    cxbyte bits;
397};
398
399// table of opcode positions in encoding (GCN1.0/1.1)
400static const GCNEncodingOpcodeBits gcnEncodingOpcodeTable[GCNENC_MAXVAL+1] =
401{
402    { 0, 0 },
403    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
404    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
405    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
406    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
407    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
408    { 22, 6 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
409    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
410    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
411    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
412    { 17, 9 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
413    { 17, 9 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
414    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
415    { 18, 8 }, /* GCNENC_DS, opcode = (8bit)<<18 */
416    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
417    { 16, 3 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
418    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
419    { 0, 0 }, /* GCNENC_EXP, opcode = none */
420    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
421};
422
423// table of opcode positions in encoding (GCN1.2/1.4)
424static const GCNEncodingOpcodeBits gcnEncodingOpcode12Table[GCNENC_MAXVAL+1] =
425{
426    { 0, 0 },
427    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
428    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
429    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
430    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
431    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
432    { 18, 8 }, /* GCNENC_SMEM, opcode = (8bit)<<18 */
433    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
434    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
435    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
436    { 16, 10 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 */
437    { 16, 10 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 */
438    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
439    { 17, 8 }, /* GCNENC_DS, opcode = (8bit)<<17 */
440    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
441    { 15, 4 }, /* GCNENC_MTBUF, opcode = (4bit)<<15 */
442    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
443    { 0, 0 }, /* GCNENC_EXP, opcode = none */
444    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
445};
446
447
448/* main routine */
449
450void GCNDisassembler::disassemble()
451{
452    // select current label and reloc to first
453    LabelIter curLabel = std::lower_bound(labels.begin(), labels.end(), labelStartOffset);
454    RelocIter curReloc = std::lower_bound(relocations.begin(), relocations.end(),
455        std::make_pair(startOffset, Relocation()),
456          [](const std::pair<size_t,Relocation>& a, const std::pair<size_t, Relocation>& b)
457          { return a.first < b.first; });
458    NamedLabelIter curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
459        std::make_pair(labelStartOffset, CString()),
460          [](const std::pair<size_t,CString>& a, const std::pair<size_t, CString>& b)
461          { return a.first < b.first; });
462   
463    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
464
465    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
466                disassembler.getDeviceType());
467    // set up GCN indicators
468    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
469    const bool isGCN124 = (arch >= GPUArchitecture::GCN1_2);
470    const bool isGCN14 = (arch >= GPUArchitecture::GCN1_4);
471    const uint16_t curArchMask = 
472            1U<<int(getGPUArchitectureFromDeviceType(disassembler.getDeviceType()));
473    const size_t codeWordsNum = (inputSize>>2);
474   
475    if ((inputSize&3) != 0)
476        output.write(64,
477           "        /* WARNING: Code size is not aligned to 4-byte word! */\n");
478    if (instrOutOfCode)
479        output.write(54, "        /* WARNING: Unfinished instruction at end! */\n");
480   
481    bool prevIsTwoWord = false;
482   
483    size_t pos = 0;
484    while (true)
485    {
486        writeLabelsToPosition(pos<<2, curLabel, curNamedLabel);
487        if (pos >= codeWordsNum)
488            break;
489       
490        const size_t oldPos = pos;
491        cxbyte gcnEncoding = GCNENC_NONE;
492        const uint32_t insnCode = ULEV(codeWords[pos++]);
493        if (insnCode == 0)
494        {
495            /* fix for GalliumCOmpute disassemblying (assembler doesn't accep
496             * with two scalar operands */
497            size_t count;
498            for (count = 1; pos < codeWordsNum && codeWords[pos]==0; count++, pos++);
499            // put to output
500            char* buf = output.reserve(40);
501            size_t bufPos = 0;
502            memcpy(buf+bufPos, ".fill ", 6);
503            bufPos += 6;
504            bufPos += itocstrCStyle(count, buf+bufPos, 20);
505            memcpy(buf+bufPos, ", 4, 0\n", 7);
506            bufPos += 7;
507            output.forward(bufPos);
508            continue;
509        }
510        uint32_t insnCode2 = 0;
511       
512       
513        /* determine GCN encoding */
514        if ((insnCode & 0x80000000U) != 0)
515        {
516            if ((insnCode & 0x40000000U) == 0)
517            {
518                // SOP???
519                if  ((insnCode & 0x30000000U) == 0x30000000U)
520                {
521                    // SOP1/SOPK/SOPC/SOPP
522                    const uint32_t encPart = (insnCode & 0x0f800000U);
523                    if (encPart == 0x0e800000U)
524                    {
525                        // SOP1
526                        if ((insnCode&0xff) == 0xff) // literal
527                        {
528                            if (pos < codeWordsNum)
529                                insnCode2 = ULEV(codeWords[pos++]);
530                        }
531                        gcnEncoding = GCNENC_SOP1;
532                    }
533                    else if (encPart == 0x0f000000U)
534                    {
535                        // SOPC
536                        if ((insnCode&0xff) == 0xff ||
537                            (insnCode&0xff00) == 0xff00) // literal
538                        {
539                            if (pos < codeWordsNum)
540                                insnCode2 = ULEV(codeWords[pos++]);
541                        }
542                        gcnEncoding = GCNENC_SOPC;
543                    }
544                    else if (encPart == 0x0f800000U) // SOPP
545                        gcnEncoding = GCNENC_SOPP;
546                    else // SOPK
547                    {
548                        gcnEncoding = GCNENC_SOPK;
549                        const uint32_t opcode = ((insnCode>>23)&0x1f);
550                        if ((!isGCN124 && opcode == 21) ||
551                            (isGCN124 && opcode == 20))
552                        {
553                            if (pos < codeWordsNum)
554                                insnCode2 = ULEV(codeWords[pos++]);
555                        }
556                    }
557                }
558                else
559                {
560                    // SOP2
561                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
562                    {
563                        // literal
564                        if (pos < codeWordsNum)
565                            insnCode2 = ULEV(codeWords[pos++]);
566                    }
567                    gcnEncoding = GCNENC_SOP2;
568                }
569            }
570            else
571            {
572                // SMRD and others
573                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
574                if ((!isGCN124 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
575                    (isGCN124 && gcnSize12Table[encPart]))
576                {
577                    if (pos < codeWordsNum)
578                        insnCode2 = ULEV(codeWords[pos++]);
579                }
580                if (isGCN124)
581                    gcnEncoding = gcnEncoding12Table[encPart];
582                else
583                    gcnEncoding = gcnEncoding11Table[encPart];
584                if (gcnEncoding == GCNENC_FLAT && !isGCN11 && !isGCN124)
585                    gcnEncoding = GCNENC_NONE; // illegal if not GCN1.1
586            }
587        }
588        else
589        {
590            // some vector instructions
591            if ((insnCode & 0x7e000000U) == 0x7c000000U)
592            {
593                // VOPC
594                if ((insnCode&0x1ff) == 0xff || // literal
595                    // SDWA, DDP
596                    (isGCN124 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
597                {
598                    if (pos < codeWordsNum)
599                        insnCode2 = ULEV(codeWords[pos++]);
600                }
601                gcnEncoding = GCNENC_VOPC;
602            }
603            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
604            {
605                // VOP1
606                if ((insnCode&0x1ff) == 0xff || // literal
607                    // SDWA, DDP
608                    (isGCN124 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
609                {
610                    if (pos < codeWordsNum)
611                        insnCode2 = ULEV(codeWords[pos++]);
612                }
613                gcnEncoding = GCNENC_VOP1;
614            }
615            else
616            {
617                // VOP2
618                const cxuint opcode = (insnCode >> 25)&0x3f;
619                if ((!isGCN124 && (opcode == 32 || opcode == 33)) ||
620                    (isGCN124 && (opcode == 23 || opcode == 24 ||
621                    opcode == 36 || opcode == 37))) // V_MADMK and V_MADAK
622                {
623                    if (pos < codeWordsNum)
624                        insnCode2 = ULEV(codeWords[pos++]);
625                }
626                else if ((insnCode&0x1ff) == 0xff || // literal
627                    // SDWA, DDP
628                    (isGCN124 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
629                {
630                    if (pos < codeWordsNum)
631                        insnCode2 = ULEV(codeWords[pos++]);
632                }
633                gcnEncoding = GCNENC_VOP2;
634            }
635        }
636       
637        prevIsTwoWord = (oldPos+2 == pos);
638       
639        if (disassembler.getFlags() & DISASM_HEXCODE)
640        {
641            char* buf = output.reserve(50);
642            size_t bufPos = 0;
643            buf[bufPos++] = '/';
644            buf[bufPos++] = '*';
645            if (disassembler.getFlags() & DISASM_CODEPOS)
646            {
647                // print code position
648                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
649                                buf+bufPos, 20, 16, 12, false);
650                buf[bufPos++] = ':';
651                buf[bufPos++] = ' ';
652            }
653            bufPos += itocstrCStyle(insnCode, buf+bufPos, 12, 16, 8, false);
654            buf[bufPos++] = ' ';
655            // if instruction is two word long
656            if (prevIsTwoWord)
657                bufPos += itocstrCStyle(insnCode2, buf+bufPos, 12, 16, 8, false);
658            else
659                bufPos += addSpacesOld(buf+bufPos, 8);
660            buf[bufPos++] = '*';
661            buf[bufPos++] = '/';
662            buf[bufPos++] = ' ';
663            output.forward(bufPos);
664        }
665        else // add spaces
666        {
667            if (disassembler.getFlags() & DISASM_CODEPOS)
668            {
669                // print only code position
670                char* buf = output.reserve(30);
671                size_t bufPos = 0;
672                buf[bufPos++] = '/';
673                buf[bufPos++] = '*';
674                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
675                                buf+bufPos, 20, 16, 12, false);
676                buf[bufPos++] = '*';
677                buf[bufPos++] = '/';
678                buf[bufPos++] = ' ';
679                output.forward(bufPos);
680            }
681            else
682            {
683                // add spaces
684                char* buf = output.reserve(8);
685                output.forward(addSpacesOld(buf, 8));
686            }
687        }
688       
689        if (gcnEncoding == GCNENC_NONE)
690        {
691            // invalid encoding
692            char* buf = output.reserve(24);
693            size_t bufPos = 0;
694            buf[bufPos++] = '.';
695            buf[bufPos++] = 'i';
696            buf[bufPos++] = 'n';
697            buf[bufPos++] = 't';
698            buf[bufPos++] = ' '; 
699            bufPos += itocstrCStyle(insnCode, buf+bufPos, 11, 16);
700            output.forward(bufPos);
701        }
702        else
703        {
704            const GCNEncodingOpcodeBits* encodingOpcodeTable = 
705                    (isGCN124) ? gcnEncodingOpcode12Table : gcnEncodingOpcodeTable;
706            const cxuint opcode =
707                    (insnCode>>encodingOpcodeTable[gcnEncoding].bitPos) & 
708                    ((1U<<encodingOpcodeTable[gcnEncoding].bits)-1U);
709           
710            /* decode instruction and put to output */
711            const GCNEncodingSpace& encSpace = 
712                (isGCN124) ? gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+3 + gcnEncoding] :
713                  gcnInstrTableByCodeSpaces[gcnEncoding];
714            const GCNInstruction* gcnInsn = gcnInstrTableByCode.get() +
715                    encSpace.offset + opcode;
716           
717            const GCNInstruction defaultInsn = { nullptr, gcnInsn->encoding, GCN_STDMODE,
718                        0, 0 };
719            cxuint spacesToAdd = 16;
720            bool isIllegal = false;
721            if (!isGCN124 && gcnInsn->mnemonic != nullptr &&
722                (curArchMask & gcnInsn->archMask) == 0 &&
723                gcnEncoding == GCNENC_VOP3A)
724            {    /* new overrides (VOP3A) */
725                const GCNEncodingSpace& encSpace2 =
726                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
727                gcnInsn = gcnInstrTableByCode.get() + encSpace2.offset + opcode;
728                if (gcnInsn->mnemonic == nullptr ||
729                        (curArchMask & gcnInsn->archMask) == 0)
730                    isIllegal = true; // illegal
731            }
732            else if (isGCN14 && gcnInsn->mnemonic != nullptr &&
733                (curArchMask & gcnInsn->archMask) == 0 &&
734                (gcnEncoding == GCNENC_VOP3A || gcnEncoding == GCNENC_VOP2 ||
735                    gcnEncoding == GCNENC_VOP1))
736            {
737                /* new overrides (VOP1/VOP3A/VOP2 for GCN 1.4) */
738                const GCNEncodingSpace& encSpace4 =
739                        gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 +
740                                (gcnEncoding != GCNENC_VOP2) +
741                                (gcnEncoding == GCNENC_VOP1)];
742                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
743                if (gcnInsn->mnemonic == nullptr ||
744                        (curArchMask & gcnInsn->archMask) == 0)
745                    isIllegal = true; // illegal
746            }
747            else if (isGCN14 && gcnEncoding == GCNENC_FLAT && ((insnCode>>14)&3)!=0)
748            {
749                // GLOBAL_/SCRATCH_* instructions
750                const GCNEncodingSpace& encSpace4 =
751                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 +
752                        ((insnCode>>14)&3)-1];
753                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
754                if (gcnInsn->mnemonic == nullptr ||
755                        (curArchMask & gcnInsn->archMask) == 0)
756                    isIllegal = true; // illegal
757            }
758            else if (gcnInsn->mnemonic == nullptr ||
759                (curArchMask & gcnInsn->archMask) == 0)
760                isIllegal = true;
761           
762            if (!isIllegal)
763            {
764                // put spaces between mnemonic and operands
765                size_t k = ::strlen(gcnInsn->mnemonic);
766                output.writeString(gcnInsn->mnemonic);
767                spacesToAdd = spacesToAdd>=k+1?spacesToAdd-k:1;
768            }
769            else
770            {
771                // print illegal instruction mnemonic
772                char* bufStart = output.reserve(40);
773                char* bufPtr = bufStart;
774                if (!isGCN124 || gcnEncoding != GCNENC_SMEM)
775                    putChars(bufPtr, gcnEncodingNames[gcnEncoding],
776                            ::strlen(gcnEncodingNames[gcnEncoding]));
777                else /* SMEM encoding */
778                    putChars(bufPtr, "SMEM", 4);
779                putChars(bufPtr, "_ill_", 5);
780                // opcode value
781                bufPtr += itocstrCStyle(opcode, bufPtr , 6);
782                const size_t linePos = bufPtr-bufStart;
783                spacesToAdd = spacesToAdd >= (linePos+1)? spacesToAdd - linePos : 1;
784                gcnInsn = &defaultInsn;
785                output.forward(bufPtr-bufStart);
786            }
787           
788            // determine float literal type to display
789            const FloatLitType displayFloatLits = 
790                    ((disassembler.getFlags()&DISASM_FLOATLITS) != 0) ?
791                    (((gcnInsn->mode & GCN_MASK2) == GCN_FLOATLIT) ? FLTLIT_F32 : 
792                    ((gcnInsn->mode & GCN_MASK2) == GCN_F16LIT) ? FLTLIT_F16 :
793                     FLTLIT_NONE) : FLTLIT_NONE;
794           
795            // print instruction in correct encoding
796            switch(gcnEncoding)
797            {
798                case GCNENC_SOPC:
799                    GCNDisasmUtils::decodeSOPCEncoding(*this, pos, curReloc,
800                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
801                    break;
802                case GCNENC_SOPP:
803                    GCNDisasmUtils::decodeSOPPEncoding(*this, spacesToAdd, curArchMask, 
804                                 *gcnInsn, insnCode, insnCode2, pos);
805                    break;
806                case GCNENC_SOP1:
807                    GCNDisasmUtils::decodeSOP1Encoding(*this, pos, curReloc,
808                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
809                    break;
810                case GCNENC_SOP2:
811                    GCNDisasmUtils::decodeSOP2Encoding(*this, pos, curReloc,
812                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
813                    break;
814                case GCNENC_SOPK:
815                    GCNDisasmUtils::decodeSOPKEncoding(*this, pos, curReloc,
816                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
817                    break;
818                case GCNENC_SMRD:
819                    if (isGCN124)
820                        GCNDisasmUtils::decodeSMEMEncoding(*this, spacesToAdd, curArchMask,
821                                  *gcnInsn, insnCode, insnCode2);
822                    else
823                        GCNDisasmUtils::decodeSMRDEncoding(*this, spacesToAdd, curArchMask,
824                                  *gcnInsn, insnCode);
825                    break;
826                case GCNENC_VOPC:
827                    GCNDisasmUtils::decodeVOPCEncoding(*this, pos, curReloc, spacesToAdd,
828                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
829                    break;
830                case GCNENC_VOP1:
831                    GCNDisasmUtils::decodeVOP1Encoding(*this, pos, curReloc, spacesToAdd,
832                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
833                    break;
834                case GCNENC_VOP2:
835                    GCNDisasmUtils::decodeVOP2Encoding(*this, pos, curReloc, spacesToAdd,
836                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
837                    break;
838                case GCNENC_VOP3A:
839                    GCNDisasmUtils::decodeVOP3Encoding(*this, spacesToAdd, curArchMask,
840                                 *gcnInsn, insnCode, insnCode2, displayFloatLits);
841                    break;
842                case GCNENC_VINTRP:
843                    GCNDisasmUtils::decodeVINTRPEncoding(*this, spacesToAdd, curArchMask,
844                                 *gcnInsn, insnCode);
845                    break;
846                case GCNENC_DS:
847                    GCNDisasmUtils::decodeDSEncoding(*this, spacesToAdd, curArchMask,
848                                 *gcnInsn, insnCode, insnCode2);
849                    break;
850                case GCNENC_MUBUF:
851                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
852                                 *gcnInsn, insnCode, insnCode2);
853                    break;
854                case GCNENC_MTBUF:
855                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
856                                 *gcnInsn, insnCode, insnCode2);
857                    break;
858                case GCNENC_MIMG:
859                    GCNDisasmUtils::decodeMIMGEncoding(*this, spacesToAdd, curArchMask,
860                                 *gcnInsn, insnCode, insnCode2);
861                    break;
862                case GCNENC_EXP:
863                    GCNDisasmUtils::decodeEXPEncoding(*this, spacesToAdd, curArchMask,
864                                 *gcnInsn, insnCode, insnCode2);
865                    break;
866                case GCNENC_FLAT:
867                    GCNDisasmUtils::decodeFLATEncoding(*this, spacesToAdd, curArchMask,
868                                 *gcnInsn, insnCode, insnCode2);
869                    break;
870                default:
871                    break;
872            }
873        }
874        output.put('\n');
875    }
876    if (!dontPrintLabelsAfterCode)
877        writeLabelsToEnd(codeWordsNum<<2, curLabel, curNamedLabel);
878    output.flush();
879    disassembler.getOutput().flush();
880}
Note: See TracBrowser for help on using the repository browser.