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

Last change on this file since 4997 was 4997, checked in by matszpk, 11 months ago

CLRadeonExtender: GCNDisasm: Add support for SMRD immediate 32-bit literal for offset if arch==GCN1.1. Some changes in assembler.

File size: 48.7 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[] =
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    // GFX10 -
117    { 0x1e62+0, 0x80 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
118    { 0x1e62+0x0080, 0x80 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
119    { 0x1e62+0x0100, 0x100 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
120    { 0x1e62+0x0200, 0x80 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
121    { 0x1e62+0x0280, 0x20 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
122    { 0x1e62+0x02a0, 0x100 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
123    { 0x1e62+0x03a0, 0x100 }, /* GCNENC_VOPC, opcode = (8bit)<<27 */
124    { 0x1e62+0x04a0, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
125    { 0x1e62+0x05a0, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
126    { 0x1e62+0x05e0, 0x400 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
127    { 0x1e62+0x05e0, 0x400 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
128    { 0x1e62+0x09e0, 0x4 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
129    { 0x1e62+0x09e4, 0x100 }, /* GCNENC_DS, opcode = (8bit)<<18 */
130    { 0x1e62+0x0ae4, 0x80 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
131    { 0x1e62+0x0b64, 0x10 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
132    { 0x1e62+0x0b74, 0x80 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
133    { 0x1e62+0x0bf4, 0x1 }, /* GCNENC_EXP, opcode = none */
134    { 0x1e62+0x0bf5, 0x80 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
135    { 0x1e62+0x0c75, 0x80 }, /* GCNENC_VOP3P */
136    { 0x1e62+0x0cf5, 0x80 }, /* GCNENC_FLAT_SCRATCH, opcode = (8bit)<<18 (???8bit) */
137    { 0x1e62+0x0d75, 0x80 }, /* GCNENC_FLAT_GLOBAL, opcode = (8bit)<<18 (???8bit) */
138};
139
140// total instruction table length
141static const size_t gcnInstrTableByCodeLength = 0x1e62 + 0x0df5;
142
143enum: cxuint {
144    GCN_GFX10_ENCSPACE_IDX = 44
145};
146
147// create main instruction table
148static void initializeGCNDisassembler()
149{
150    gcnInstrTableByCode.reset(new GCNInstruction[gcnInstrTableByCodeLength]);
151    for (cxuint i = 0; i < gcnInstrTableByCodeLength; i++)
152    {
153        gcnInstrTableByCode[i].mnemonic = nullptr;
154        gcnInstrTableByCode[i].mode = GCN_STDMODE;
155        // except VOP3 decoding routines ignores encoding (we can set None for encoding)
156        gcnInstrTableByCode[i].encoding = GCNENC_NONE;
157    }
158   
159    // fill up main instruction table
160    for (cxuint i = 0; gcnInstrsTable[i].mnemonic != nullptr; i++)
161    {
162        const GCNInstruction& instr = gcnInstrsTable[i];
163        const GCNEncodingSpace& encSpace = gcnInstrTableByCodeSpaces[instr.encoding];
164        if ((instr.archMask & ARCH_GCN_1_0_1) != 0)
165        {
166            if (gcnInstrTableByCode[encSpace.offset + instr.code].mnemonic == nullptr)
167                gcnInstrTableByCode[encSpace.offset + instr.code] = instr;
168            else if((instr.archMask & ARCH_RX2X0) != 0)
169            {
170                /* otherwise we for GCN1.1 */
171                const GCNEncodingSpace& encSpace2 =
172                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
173                gcnInstrTableByCode[encSpace2.offset + instr.code] = instr;
174            }
175            // otherwise we ignore this entry
176        }
177        if ((instr.archMask & ARCH_GCN_1_2_4) != 0)
178        {
179            // for GCN 1.2/1.4
180            const GCNEncodingSpace& encSpace3 = gcnInstrTableByCodeSpaces[
181                        GCNENC_MAXVAL+3+instr.encoding];
182            if (gcnInstrTableByCode[encSpace3.offset + instr.code].mnemonic == nullptr)
183                gcnInstrTableByCode[encSpace3.offset + instr.code] = instr;
184            else if((instr.archMask & ARCH_GCN_1_4) != 0 &&
185                (instr.encoding == GCNENC_VOP2 || instr.encoding == GCNENC_VOP1 ||
186                instr.encoding == GCNENC_VOP3A || instr.encoding == GCNENC_VOP3B))
187            {
188                /* otherwise we for GCN1.4 */
189                const bool encNoVOP2 = instr.encoding != GCNENC_VOP2;
190                const bool encVOP1 = instr.encoding == GCNENC_VOP1;
191                // choose FLAT_GLOBAL or FLAT_SCRATCH space
192                const GCNEncodingSpace& encSpace4 =
193                    gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 + encNoVOP2 + encVOP1];
194                gcnInstrTableByCode[encSpace4.offset + instr.code] = instr;
195            }
196            else if((instr.archMask & ARCH_GCN_1_4) != 0 &&
197                instr.encoding == GCNENC_FLAT && (instr.mode & GCN_FLAT_MODEMASK) != 0)
198            {
199                /* FLAT SCRATCH and GLOBAL instructions */
200                const cxuint encFlatMode = (instr.mode & GCN_FLAT_MODEMASK)-1;
201                const GCNEncodingSpace& encSpace4 =
202                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 + encFlatMode];
203                gcnInstrTableByCode[encSpace4.offset + instr.code] = instr;
204            }
205            // otherwise we ignore this entry
206        }
207       
208        if ((instr.archMask & ARCH_GCN_1_5) != 0)
209        {
210            if (instr.encoding != GCNENC_FLAT || (instr.mode & GCN_FLAT_MODEMASK) == 0)
211            {
212                const GCNEncodingSpace& encSpace = gcnInstrTableByCodeSpaces[
213                            GCN_GFX10_ENCSPACE_IDX + instr.encoding];
214                if (gcnInstrTableByCode[encSpace.offset + instr.code].mnemonic == nullptr ||
215                    ((instr.archMask == ARCH_GCN_1_5) &&
216                    (gcnInstrTableByCode[encSpace.offset + instr.code].archMask) !=
217                            ARCH_GCN_1_5))
218                    gcnInstrTableByCode[encSpace.offset + instr.code] = instr;
219            }
220            else
221            {
222                const cxuint encFlatMode = (instr.mode & GCN_FLAT_MODEMASK);
223                const GCNEncodingSpace& encSpace = gcnInstrTableByCodeSpaces[
224                            GCN_GFX10_ENCSPACE_IDX + GCNENC_VOP3P + encFlatMode];
225                if (gcnInstrTableByCode[encSpace.offset + instr.code].mnemonic == nullptr ||
226                    ((instr.archMask == ARCH_GCN_1_5) &&
227                    (gcnInstrTableByCode[encSpace.offset + instr.code].archMask) !=
228                            ARCH_GCN_1_5))
229                    gcnInstrTableByCode[encSpace.offset + instr.code] = instr;
230            }
231        }
232    }
233}
234
235GCNDisassembler::GCNDisassembler(Disassembler& disassembler)
236        : ISADisassembler(disassembler), instrOutOfCode(false)
237{
238    callOnce(clrxGCNDisasmOnceFlag, initializeGCNDisassembler);
239}
240
241GCNDisassembler::~GCNDisassembler()
242{ }
243
244enum : cxbyte
245{
246    GCNENCSCH_1DWORD = 0,
247    GCNENCSCH_2DWORD,
248    GCNENCSCH_MIMG_DWORDS
249};
250
251// gcn encoding sizes table: true - if 8 byte encoding, false - 4 byte encoding
252// for GCN1.0/1.1
253static const cxbyte gcnSize11Table[16] =
254{
255    GCNENCSCH_1DWORD, // GCNENC_SMRD, // 0000
256    GCNENCSCH_1DWORD, // GCNENC_SMRD, // 0001
257    GCNENCSCH_1DWORD, // GCNENC_VINTRP, // 0010
258    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0011 - illegal
259    GCNENCSCH_2DWORD,  // GCNENC_VOP3A, // 0100
260    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0101 - illegal
261    GCNENCSCH_2DWORD,  // GCNENC_DS,   // 0110
262    GCNENCSCH_2DWORD,  // GCNENC_FLAT, // 0111
263    GCNENCSCH_2DWORD,  // GCNENC_MUBUF, // 1000
264    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1001 - illegal
265    GCNENCSCH_2DWORD,  // GCNENC_MTBUF, // 1010
266    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1011 - illegal
267    GCNENCSCH_2DWORD,  // GCNENC_MIMG,  // 1100
268    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1101 - illegal
269    GCNENCSCH_2DWORD,  // GCNENC_EXP,   // 1110
270    GCNENCSCH_1DWORD // GCNENC_NONE   // 1111 - illegal
271};
272
273// for GCN1.2/1.4
274static const cxbyte gcnSize12Table[16] =
275{
276    GCNENCSCH_2DWORD,  // GCNENC_SMEM, // 0000
277    GCNENCSCH_2DWORD,  // GCNENC_EXP, // 0001
278    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0010 - illegal
279    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0011 - illegal
280    GCNENCSCH_2DWORD,  // GCNENC_VOP3A, // 0100
281    GCNENCSCH_1DWORD, // GCNENC_VINTRP, // 0101
282    GCNENCSCH_2DWORD,  // GCNENC_DS,   // 0110
283    GCNENCSCH_2DWORD,  // GCNENC_FLAT, // 0111
284    GCNENCSCH_2DWORD,  // GCNENC_MUBUF, // 1000
285    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1001 - illegal
286    GCNENCSCH_2DWORD,  // GCNENC_MTBUF, // 1010
287    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1011 - illegal
288    GCNENCSCH_2DWORD,  // GCNENC_MIMG,  // 1100
289    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1101 - illegal
290    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1110 - illegal
291    GCNENCSCH_1DWORD // GCNENC_NONE   // 1111 - illegal
292};
293
294static const cxbyte gcnSize15Table[16] =
295{
296    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0000
297    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0001
298    GCNENCSCH_1DWORD, // CNENC_VINTRP, // 0010
299    GCNENCSCH_2DWORD,  // GCNENC_VOP3P, // 0011
300    GCNENCSCH_1DWORD, // GCNENC_NONE, // 0100
301    GCNENCSCH_2DWORD,  // GCNENC_VOP3A, // 0101
302    GCNENCSCH_2DWORD,  // GCNENC_DS,   // 0110
303    GCNENCSCH_2DWORD,  // GCNENC_FLAT, // 0111
304    GCNENCSCH_2DWORD,  // GCNENC_MUBUF, // 1000
305    GCNENCSCH_1DWORD, // GCNENC_NONE, // 1001 - illegal
306    GCNENCSCH_2DWORD,  // GCNENC_MTBUF, // 1010
307    GCNENCSCH_1DWORD, // GCNENC_NONE,  // 1011 - illegal
308    GCNENCSCH_MIMG_DWORDS,  // GCNENC_MIMG,  // 1100
309    GCNENCSCH_2DWORD,  // GCNENC_SMEM,  // 1101
310    GCNENCSCH_2DWORD,  // GCNENC_EXP,   // 1110
311    GCNENCSCH_1DWORD // GCNENC_NONE   // 1111 - illegal
312};
313
314void GCNDisassembler::analyzeBeforeDisassemble()
315{
316    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
317    const size_t codeWordsNum = (inputSize>>2);
318
319    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
320                disassembler.getDeviceType());
321    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
322    const bool isGCN12 = (arch >= GPUArchitecture::GCN1_2);
323    const bool isGCN14 = (arch == GPUArchitecture::GCN1_4 || arch == GPUArchitecture::GCN1_4_1);
324    const bool isGCN15 = (arch >= GPUArchitecture::GCN1_5 || arch == GPUArchitecture::GCN1_5_1);
325    size_t pos;
326    for (pos = 0; pos < codeWordsNum; pos++)
327    {
328        /* scan all instructions and get jump addresses */
329        const uint32_t insnCode = ULEV(codeWords[pos]);
330        if ((insnCode & 0x80000000U) != 0)
331        {
332            if ((insnCode & 0x40000000U) == 0)
333            {
334                // SOP???
335                if  ((insnCode & 0x30000000U) == 0x30000000U)
336                {
337                    // SOP1/SOPK/SOPC/SOPP
338                    const uint32_t encPart = (insnCode & 0x0f800000U);
339                    if (encPart == 0x0e800000U)
340                    {
341                        // SOP1
342                        if ((insnCode&0xff) == 0xff) // literal
343                            pos++;
344                    }
345                    else if (encPart == 0x0f000000U)
346                    {
347                        // SOPC
348                        if ((insnCode&0xff) == 0xff ||
349                            (insnCode&0xff00) == 0xff00) // literal
350                            pos++;
351                    }
352                    else if (encPart == 0x0f800000U)
353                    {
354                        // SOPP
355                        const cxuint opcode = (insnCode>>16)&0x7f;
356                        if (opcode == 2 || (opcode >= 4 && opcode <= 9) ||
357                            // GCN1.1 and GCN1.2 opcodes
358                            ((isGCN11 || isGCN12) &&
359                                    (opcode >= 23 && opcode <= 26))) // if jump
360                            labels.push_back(startOffset +
361                                    ((pos+int16_t(insnCode&0xffff)+1)<<2));
362                    }
363                    else
364                    {
365                        // SOPK
366                        const cxuint opcode = (insnCode>>23)&0x1f;
367                        if ((!isGCN12 && opcode == 17) ||
368                            (isGCN12 && opcode == 16) || // if branch fork
369                            (isGCN14 && opcode == 21) || // if s_call_b64
370                            (isGCN15 && (opcode == 22 ||
371                                opcode == 27 || opcode == 28))) // if s_subvector_loop_*
372                            labels.push_back(startOffset +
373                                    ((pos+int16_t(insnCode&0xffff)+1)<<2));
374                        else if (((!isGCN12 || isGCN15) && opcode == 21) ||
375                            (isGCN12 && !isGCN15 && opcode == 20))
376                            pos++; // additional literal
377                    }
378                }
379                else
380                {
381                    // SOP2
382                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
383                        pos++;  // literal
384                }
385            }
386            else
387            {
388                // SMRD and others
389                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
390                if (isGCN15)
391                {
392                    if (gcnSize15Table[encPart]==GCNENCSCH_MIMG_DWORDS)
393                        pos += ((insnCode>>1)&3) + 1;
394                    else if (gcnSize15Table[encPart])
395                        pos++;
396                }
397                else if (isGCN11 && encPart==0 && (insnCode&0x1ff)==0xff)
398                    pos++;
399                else if ((!isGCN12 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
400                    (isGCN12 && gcnSize12Table[encPart]))
401                    pos++;
402                if (isGCN15 && (encPart==3 || encPart==5))
403                {
404                    // include VOP3 literal
405                    const uint32_t insnCode2 = ULEV(codeWords[pos]);
406                    if ((insnCode2 & 0x1ff) == 0xff || ((insnCode2>>9) & 0x1ff) == 0xff ||
407                        ((insnCode2>>18) & 0x1ff) == 0xff)
408                        pos++;
409                }
410            }
411        }
412        else
413        {
414            uint32_t src0 = (insnCode&0x1ff);
415            // some vector instructions
416            if ((insnCode & 0x7e000000U) == 0x7c000000U)
417            {
418                // VOPC
419                if (src0 == 0xff || // literal
420                    // SDWA, DPP
421                    (isGCN12 && (src0 == 0xf9 || src0 == 0xfa)) ||
422                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
423                    pos++;
424            }
425            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
426            {
427                // VOP1
428                if (src0 == 0xff || // literal
429                    // SDWA, DPP
430                    (isGCN12 && (src0 == 0xf9 || src0 == 0xfa)) ||
431                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
432                    pos++;
433            }
434            else
435            {
436                // VOP2
437                const cxuint opcode = (insnCode >> 25)&0x3f;
438                if ((!isGCN12 && (opcode == 32 || opcode == 33)) ||
439                    (isGCN12 && !isGCN15 && (opcode == 23 || opcode == 24 ||
440                    opcode == 36 || opcode == 37)) ||
441                    (isGCN15 && (opcode == 32 || opcode == 33 || // V_MADMK and V_MADAK
442                        opcode == 44 || opcode == 45 || // V_FMAMK_F32, V_FMAAK_F32
443                        opcode == 55 || opcode == 56))) // V_FMAMK_F16, V_FMAAK_F16
444                    pos++;  // inline 32-bit constant
445                else if (src0 == 0xff || // literal
446                    // SDWA, DPP
447                    (isGCN12 && (src0 == 0xf9 || src0 == 0xfa)) ||
448                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
449                    pos++;  // literal
450            }
451        }
452    }
453   
454    instrOutOfCode = (pos != codeWordsNum);
455}
456
457static const cxbyte gcnEncoding11Table[16] =
458{
459    GCNENC_SMRD, // 0000
460    GCNENC_SMRD, // 0001
461    GCNENC_VINTRP, // 0010
462    GCNENC_NONE, // 0011 - illegal
463    GCNENC_VOP3A, // 0100
464    GCNENC_NONE, // 0101 - illegal
465    GCNENC_DS,   // 0110
466    GCNENC_FLAT, // 0111
467    GCNENC_MUBUF, // 1000
468    GCNENC_NONE,  // 1001 - illegal
469    GCNENC_MTBUF, // 1010
470    GCNENC_NONE,  // 1011 - illegal
471    GCNENC_MIMG,  // 1100
472    GCNENC_NONE,  // 1101 - illegal
473    GCNENC_EXP,   // 1110
474    GCNENC_NONE   // 1111 - illegal
475};
476
477static const cxbyte gcnEncoding12Table[16] =
478{
479    GCNENC_SMEM, // 0000
480    GCNENC_EXP, // 0001
481    GCNENC_NONE, // 0010 - illegal
482    GCNENC_NONE, // 0011 - illegal
483    GCNENC_VOP3A, // 0100
484    GCNENC_VINTRP, // 0101
485    GCNENC_DS,   // 0110
486    GCNENC_FLAT, // 0111
487    GCNENC_MUBUF, // 1000
488    GCNENC_NONE,  // 1001 - illegal
489    GCNENC_MTBUF, // 1010
490    GCNENC_NONE,  // 1011 - illegal
491    GCNENC_MIMG,  // 1100
492    GCNENC_NONE,  // 1101 - illegal
493    GCNENC_NONE,  // 1110 - illegal
494    GCNENC_NONE   // 1111 - illegal
495};
496
497static const cxbyte gcnEncoding15Table[16] =
498{
499    GCNENC_NONE, // 0000
500    GCNENC_NONE, // 0001
501    GCNENC_VINTRP, // 0010
502    GCNENC_VOP3P, // 0011
503    GCNENC_NONE, // 0100
504    GCNENC_VOP3A, // 0101
505    GCNENC_DS,   // 0110
506    GCNENC_FLAT, // 0111
507    GCNENC_MUBUF, // 1000
508    GCNENC_NONE, // 1001 - illegal
509    GCNENC_MTBUF, // 1010
510    GCNENC_NONE,  // 1011 - illegal
511    GCNENC_MIMG,  // 1100
512    GCNENC_SMEM,  // 1101
513    GCNENC_EXP,   // 1110
514    GCNENC_NONE   // 1111 - illegal
515};
516
517
518struct CLRX_INTERNAL GCNEncodingOpcodeBits
519{
520    cxbyte bitPos;
521    cxbyte bits;
522    cxbyte bitPos2;
523    cxbyte bits2;
524};
525
526// table of opcode positions in encoding (GCN1.0/1.1)
527static const GCNEncodingOpcodeBits gcnEncodingOpcodeTable[GCNENC_MAXVAL+1] =
528{
529    { 0, 0 },
530    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
531    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
532    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
533    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
534    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
535    { 22, 6 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
536    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
537    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
538    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
539    { 17, 9 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
540    { 17, 9 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
541    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
542    { 18, 8 }, /* GCNENC_DS, opcode = (8bit)<<18 */
543    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
544    { 16, 3 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
545    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
546    { 0, 0 }, /* GCNENC_EXP, opcode = none */
547    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
548};
549
550// table of opcode positions in encoding (GCN1.2/1.4)
551static const GCNEncodingOpcodeBits gcnEncodingOpcode12Table[GCNENC_MAXVAL+1] =
552{
553    { 0, 0 },
554    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
555    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
556    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
557    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
558    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
559    { 18, 8 }, /* GCNENC_SMEM, opcode = (8bit)<<18 */
560    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
561    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
562    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
563    { 16, 10 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 */
564    { 16, 10 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 */
565    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
566    { 17, 8 }, /* GCNENC_DS, opcode = (8bit)<<17 */
567    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
568    { 15, 4 }, /* GCNENC_MTBUF, opcode = (4bit)<<15 */
569    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
570    { 0, 0 }, /* GCNENC_EXP, opcode = none */
571    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
572};
573
574// table of opcode positions in encoding (GCN1.5)
575static const GCNEncodingOpcodeBits gcnEncodingOpcode15Table[GCNENC_MAXVAL+2] =
576{
577    { 0, 0 },
578    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
579    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
580    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
581    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
582    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
583    { 18, 8 }, /* GCNENC_SMEM, opcode = (8bit)<<18 */
584    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
585    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
586    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
587    { 16, 10 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 */
588    { 16, 10 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 */
589    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
590    { 18, 8 }, /* GCNENC_DS, opcode = (8bit)<<18 */
591    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
592    { 16, 3, 53, 1 }, /* GCNENC_MTBUF, opcode = (4bit)<<15 */ // 53-bit opcode
593    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
594    { 0, 0 }, /* GCNENC_EXP, opcode = none */
595    { 18, 7 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
596    { 16, 7 } /* GCNENC_VOP3P, opcode = (7bit)<<16 */
597};
598
599/* main routine */
600
601void GCNDisassembler::disassemble()
602{
603    // select current label and reloc to first
604    LabelIter curLabel = std::lower_bound(labels.begin(), labels.end(), labelStartOffset);
605    RelocIter curReloc = std::lower_bound(relocations.begin(), relocations.end(),
606        std::make_pair(startOffset, Relocation()),
607          [](const std::pair<size_t,Relocation>& a, const std::pair<size_t, Relocation>& b)
608          { return a.first < b.first; });
609    NamedLabelIter curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
610        std::make_pair(labelStartOffset, CString()),
611          [](const std::pair<size_t,CString>& a, const std::pair<size_t, CString>& b)
612          { return a.first < b.first; });
613   
614    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
615
616    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
617                disassembler.getDeviceType());
618    // set up GCN indicators
619    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
620    const bool isGCN124 = (arch >= GPUArchitecture::GCN1_2);
621    const bool isGCN14 = (arch == GPUArchitecture::GCN1_4 || arch == GPUArchitecture::GCN1_4_1);
622    const bool isGCN15 = (arch == GPUArchitecture::GCN1_5 || arch >= GPUArchitecture::GCN1_5_1);
623    const GPUArchMask curArchMask = 
624            1U<<int(getGPUArchitectureFromDeviceType(disassembler.getDeviceType()));
625    const size_t codeWordsNum = (inputSize>>2);
626   
627    if ((inputSize&3) != 0)
628        output.write(64,
629           "        /* WARNING: Code size is not aligned to 4-byte word! */\n");
630    if (instrOutOfCode)
631        output.write(54, "        /* WARNING: Unfinished instruction at end! */\n");
632   
633    bool prevIsTwoWord = false;
634   
635    size_t pos = 0;
636    while (true)
637    {
638        writeLabelsToPosition(pos<<2, curLabel, curNamedLabel);
639        if (pos >= codeWordsNum)
640            break;
641       
642        const size_t oldPos = pos;
643        cxbyte gcnEncoding = GCNENC_NONE;
644        const uint32_t insnCode = ULEV(codeWords[pos++]);
645        if (insnCode == 0)
646        {
647            /* fix for GalliumCOmpute disassemblying (assembler doesn't accep
648             * with two scalar operands */
649            size_t count;
650            for (count = 1; pos < codeWordsNum && codeWords[pos]==0; count++, pos++);
651            // put to output
652            char* buf = output.reserve(40);
653            size_t bufPos = 0;
654            memcpy(buf+bufPos, ".fill ", 6);
655            bufPos += 6;
656            bufPos += itocstrCStyle(count, buf+bufPos, 20);
657            memcpy(buf+bufPos, ", 4, 0\n", 7);
658            bufPos += 7;
659            output.forward(bufPos);
660            continue;
661        }
662        uint32_t insnCode2 = 0;
663        uint32_t insnCode3 = 0;
664        uint32_t insnCode4 = 0;
665        uint32_t insnCode5 = 0;
666       
667        /* determine GCN encoding */
668        if ((insnCode & 0x80000000U) != 0)
669        {
670            if ((insnCode & 0x40000000U) == 0)
671            {
672                // SOP???
673                if  ((insnCode & 0x30000000U) == 0x30000000U)
674                {
675                    // SOP1/SOPK/SOPC/SOPP
676                    const uint32_t encPart = (insnCode & 0x0f800000U);
677                    if (encPart == 0x0e800000U)
678                    {
679                        // SOP1
680                        if ((insnCode&0xff) == 0xff) // literal
681                        {
682                            if (pos < codeWordsNum)
683                                insnCode2 = ULEV(codeWords[pos++]);
684                        }
685                        gcnEncoding = GCNENC_SOP1;
686                    }
687                    else if (encPart == 0x0f000000U)
688                    {
689                        // SOPC
690                        if ((insnCode&0xff) == 0xff ||
691                            (insnCode&0xff00) == 0xff00) // literal
692                        {
693                            if (pos < codeWordsNum)
694                                insnCode2 = ULEV(codeWords[pos++]);
695                        }
696                        gcnEncoding = GCNENC_SOPC;
697                    }
698                    else if (encPart == 0x0f800000U) // SOPP
699                        gcnEncoding = GCNENC_SOPP;
700                    else // SOPK
701                    {
702                        gcnEncoding = GCNENC_SOPK;
703                        const uint32_t opcode = ((insnCode>>23)&0x1f);
704                        if (((!isGCN124 || isGCN15) && opcode == 21) ||
705                            (isGCN124 && !isGCN15 && opcode == 20))
706                        {
707                            if (pos < codeWordsNum)
708                                insnCode2 = ULEV(codeWords[pos++]);
709                        }
710                    }
711                }
712                else
713                {
714                    // SOP2
715                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
716                    {
717                        // literal
718                        if (pos < codeWordsNum)
719                            insnCode2 = ULEV(codeWords[pos++]);
720                    }
721                    gcnEncoding = GCNENC_SOP2;
722                }
723            }
724            else
725            {
726                // SMRD and others
727                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
728                if (isGCN15)
729                {
730                    if (gcnSize15Table[encPart]==GCNENCSCH_MIMG_DWORDS)
731                    {
732                        cxuint extraDwords = ((insnCode>>1)&3) + 1;
733                        if (pos+extraDwords <= codeWordsNum)
734                        {
735                            if (extraDwords>=1)
736                                insnCode2 = ULEV(codeWords[pos]);
737                            if (extraDwords>=2)
738                                insnCode3 = ULEV(codeWords[pos+1]);
739                            if (extraDwords>=3)
740                                insnCode4 = ULEV(codeWords[pos+2]);
741                            if (extraDwords>=4)
742                                insnCode5 = ULEV(codeWords[pos+3]);
743                            pos += extraDwords;
744                        }
745                    }
746                    if (gcnSize15Table[encPart] && pos < codeWordsNum)
747                        insnCode2 = ULEV(codeWords[pos++]);
748                    if (isGCN15 && (encPart==3 || encPart==5))
749                    {
750                        // include VOP3 literal
751                        if ((insnCode2 & 0x1ff) == 0xff || ((insnCode2>>9) & 0x1ff) == 0xff ||
752                            ((insnCode2>>18) & 0x1ff) == 0xff)
753                            insnCode3 = ULEV(codeWords[pos++]);
754                    }
755                }
756                else if (isGCN11 && encPart==0 && (insnCode&0x1ff)==0xff)
757                {
758                    if (pos < codeWordsNum)
759                        insnCode2 = ULEV(codeWords[pos++]);
760                }
761                else if ((!isGCN124 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
762                    (isGCN124 && gcnSize12Table[encPart]))
763                {
764                    if (pos < codeWordsNum)
765                        insnCode2 = ULEV(codeWords[pos++]);
766                }
767                if (isGCN15)
768                    gcnEncoding = gcnEncoding15Table[encPart];
769                else if (isGCN124)
770                    gcnEncoding = gcnEncoding12Table[encPart];
771                else
772                    gcnEncoding = gcnEncoding11Table[encPart];
773                if (gcnEncoding == GCNENC_FLAT && !isGCN11 && !isGCN124)
774                    gcnEncoding = GCNENC_NONE; // illegal if not GCN1.1
775            }
776        }
777        else
778        {
779            // some vector instructions
780            const uint32_t src0 = (insnCode&0x1ff);
781            if ((insnCode & 0x7e000000U) == 0x7c000000U)
782            {
783                // VOPC
784                if (src0 == 0xff || // literal
785                    // SDWA, DPP
786                    (isGCN124 && (src0 == 0xf9 || src0 == 0xfa)) ||
787                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
788                {
789                    if (pos < codeWordsNum)
790                        insnCode2 = ULEV(codeWords[pos++]);
791                }
792                gcnEncoding = GCNENC_VOPC;
793            }
794            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
795            {
796                // VOP1
797                if (src0 == 0xff || // literal
798                    // SDWA, DPP
799                    (isGCN124 && (src0 == 0xf9 || src0 == 0xfa)) ||
800                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
801                {
802                    if (pos < codeWordsNum)
803                        insnCode2 = ULEV(codeWords[pos++]);
804                }
805                gcnEncoding = GCNENC_VOP1;
806            }
807            else
808            {
809                // VOP2
810                const cxuint opcode = (insnCode >> 25)&0x3f;
811                if ((!isGCN124 && (opcode == 32 || opcode == 33)) ||
812                    (isGCN124 && !isGCN15 && (opcode == 23 || opcode == 24 ||
813                    opcode == 36 || opcode == 37)) ||
814                    (isGCN15 && (opcode == 32 || opcode == 33 || // V_MADMK and V_MADAK
815                        opcode == 44 || opcode == 45 || // V_FMAMK_F32, V_FMAAK_F32
816                        opcode == 55 || opcode == 56))) // V_MADMK and V_MADAK
817                {
818                    if (pos < codeWordsNum)
819                        insnCode2 = ULEV(codeWords[pos++]);
820                }
821                else if (src0 == 0xff || // literal
822                    // SDWA, DDP
823                    (isGCN124 && (src0 == 0xf9 || src0 == 0xfa)) ||
824                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
825                {
826                    if (pos < codeWordsNum)
827                        insnCode2 = ULEV(codeWords[pos++]);
828                }
829                gcnEncoding = GCNENC_VOP2;
830            }
831        }
832       
833        prevIsTwoWord = (oldPos+2 == pos);
834       
835        if (disassembler.getFlags() & DISASM_HEXCODE)
836        {
837            char* buf = output.reserve(50);
838            size_t bufPos = 0;
839            buf[bufPos++] = '/';
840            buf[bufPos++] = '*';
841            if (disassembler.getFlags() & DISASM_CODEPOS)
842            {
843                // print code position
844                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
845                                buf+bufPos, 20, 16, 12, false);
846                buf[bufPos++] = ':';
847                buf[bufPos++] = ' ';
848            }
849            bufPos += itocstrCStyle(insnCode, buf+bufPos, 12, 16, 8, false);
850            buf[bufPos++] = ' ';
851            // if instruction is two word long
852            if (prevIsTwoWord)
853                bufPos += itocstrCStyle(insnCode2, buf+bufPos, 12, 16, 8, false);
854            else
855                bufPos += addSpacesOld(buf+bufPos, 8);
856            buf[bufPos++] = '*';
857            buf[bufPos++] = '/';
858            buf[bufPos++] = ' ';
859            output.forward(bufPos);
860        }
861        else // add spaces
862        {
863            if (disassembler.getFlags() & DISASM_CODEPOS)
864            {
865                // print only code position
866                char* buf = output.reserve(30);
867                size_t bufPos = 0;
868                buf[bufPos++] = '/';
869                buf[bufPos++] = '*';
870                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
871                                buf+bufPos, 20, 16, 12, false);
872                buf[bufPos++] = '*';
873                buf[bufPos++] = '/';
874                buf[bufPos++] = ' ';
875                output.forward(bufPos);
876            }
877            else
878            {
879                // add spaces
880                char* buf = output.reserve(8);
881                output.forward(addSpacesOld(buf, 8));
882            }
883        }
884       
885        if (isGCN15 && gcnEncoding == GCNENC_VOP3P && (insnCode & 0x3000000U)!=0)
886        {
887            // unknown encoding
888            gcnEncoding = GCNENC_NONE;
889            pos--;
890        }
891       
892        if (gcnEncoding == GCNENC_NONE)
893        {
894            // invalid encoding
895            char* buf = output.reserve(24);
896            size_t bufPos = 0;
897            buf[bufPos++] = '.';
898            buf[bufPos++] = 'i';
899            buf[bufPos++] = 'n';
900            buf[bufPos++] = 't';
901            buf[bufPos++] = ' '; 
902            bufPos += itocstrCStyle(insnCode, buf+bufPos, 11, 16);
903            output.forward(bufPos);
904        }
905        else
906        {
907            const GCNEncodingOpcodeBits* encodingOpcodeTable =
908                    (isGCN15) ? gcnEncodingOpcode15Table :
909                    ((isGCN124) ? gcnEncodingOpcode12Table : gcnEncodingOpcodeTable);
910            cxuint opcode =
911                    (insnCode>>encodingOpcodeTable[gcnEncoding].bitPos) & 
912                    ((1U<<encodingOpcodeTable[gcnEncoding].bits)-1U);
913            if (encodingOpcodeTable[gcnEncoding].bitPos2!=0)
914            {
915                // next bits in opcode
916                cxuint val = 0;
917                if (encodingOpcodeTable[gcnEncoding].bitPos2>=32)
918                    val = (insnCode2>>(encodingOpcodeTable[gcnEncoding].bitPos2-32));
919                else
920                    val = insnCode2>>(encodingOpcodeTable[gcnEncoding].bitPos2);
921                opcode |= (val&((1U<<encodingOpcodeTable[gcnEncoding].bits2)-1U)) <<
922                            encodingOpcodeTable[gcnEncoding].bits;
923            }
924           
925            /* decode instruction and put to output */
926            const GCNEncodingSpace& encSpace =
927                (isGCN15) ? gcnInstrTableByCodeSpaces[GCN_GFX10_ENCSPACE_IDX + gcnEncoding] :
928                ((isGCN124) ? gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+3 + gcnEncoding] :
929                  gcnInstrTableByCodeSpaces[gcnEncoding]);
930            const GCNInstruction* gcnInsn = gcnInstrTableByCode.get() +
931                    encSpace.offset + opcode;
932           
933            const GCNInstruction defaultInsn = { nullptr, gcnInsn->encoding, GCN_STDMODE,
934                        0, 0 };
935           
936            // try to replace by FMA_MIX for VEGA20
937            if ((curArchMask&ARCH_VEGA20) != 0 && gcnInsn->code>=928 && gcnInsn->code<=930)
938            {
939                const GCNEncodingSpace& encSpace4 =
940                    gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 + 1];
941                const GCNInstruction* thisGCNInstr =
942                        gcnInstrTableByCode.get() + encSpace4.offset + opcode;
943                if (thisGCNInstr->mnemonic != nullptr)
944                    // replace
945                    gcnInsn = thisGCNInstr;
946            }
947           
948            cxuint spacesToAdd = 16;
949            bool isIllegal = false;
950            if (!isGCN124 && gcnInsn->mnemonic != nullptr &&
951                (curArchMask & gcnInsn->archMask) == 0 &&
952                gcnEncoding == GCNENC_VOP3A)
953            {    /* new overrides (VOP3A) */
954                const GCNEncodingSpace& encSpace2 =
955                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
956                gcnInsn = gcnInstrTableByCode.get() + encSpace2.offset + opcode;
957                if (gcnInsn->mnemonic == nullptr ||
958                        (curArchMask & gcnInsn->archMask) == 0)
959                    isIllegal = true; // illegal
960            }
961            else if (isGCN14 && gcnInsn->mnemonic != nullptr &&
962                (curArchMask & gcnInsn->archMask) == 0 &&
963                (gcnEncoding == GCNENC_VOP3A || gcnEncoding == GCNENC_VOP2 ||
964                    gcnEncoding == GCNENC_VOP1))
965            {
966                /* new overrides (VOP1/VOP3A/VOP2 for GCN 1.4) */
967                const GCNEncodingSpace& encSpace4 =
968                        gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 +
969                                (gcnEncoding != GCNENC_VOP2) +
970                                (gcnEncoding == GCNENC_VOP1)];
971                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
972                if (gcnInsn->mnemonic == nullptr ||
973                        (curArchMask & gcnInsn->archMask) == 0)
974                    isIllegal = true; // illegal
975            }
976            else if (isGCN14 && gcnEncoding == GCNENC_FLAT && ((insnCode>>14)&3)!=0)
977            {
978                // GLOBAL_/SCRATCH_* instructions
979                const GCNEncodingSpace& encSpace4 =
980                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 +
981                        ((insnCode>>14)&3)-1];
982                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
983                if (gcnInsn->mnemonic == nullptr ||
984                        (curArchMask & gcnInsn->archMask) == 0)
985                    isIllegal = true; // illegal
986            }
987            else if (isGCN15 && gcnEncoding == GCNENC_FLAT && ((insnCode>>14)&3)!=0)
988            {
989                // GLOBAL_/SCRATCH_* instructions
990                const GCNEncodingSpace& encSpace4 =
991                    gcnInstrTableByCodeSpaces[GCN_GFX10_ENCSPACE_IDX + GCNENC_VOP3P +
992                        ((insnCode>>14)&3)];
993                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
994                if (gcnInsn->mnemonic == nullptr ||
995                        (curArchMask & gcnInsn->archMask) == 0)
996                    isIllegal = true; // illegal
997            }
998            else if (gcnInsn->mnemonic == nullptr ||
999                (curArchMask & gcnInsn->archMask) == 0)
1000                isIllegal = true;
1001           
1002            if (!isIllegal)
1003            {
1004                // put spaces between mnemonic and operands
1005                size_t k = ::strlen(gcnInsn->mnemonic);
1006                output.writeString(gcnInsn->mnemonic);
1007                spacesToAdd = spacesToAdd>=k+1?spacesToAdd-k:1;
1008            }
1009            else
1010            {
1011                // print illegal instruction mnemonic
1012                char* bufStart = output.reserve(40);
1013                char* bufPtr = bufStart;
1014                if (!isGCN124 || gcnEncoding != GCNENC_SMEM)
1015                    putChars(bufPtr, gcnEncodingNames[gcnEncoding],
1016                            ::strlen(gcnEncodingNames[gcnEncoding]));
1017                else /* SMEM encoding */
1018                    putChars(bufPtr, "SMEM", 4);
1019                putChars(bufPtr, "_ill_", 5);
1020                // opcode value
1021                bufPtr += itocstrCStyle(opcode, bufPtr , 6);
1022                const size_t linePos = bufPtr-bufStart;
1023                spacesToAdd = spacesToAdd >= (linePos+1)? spacesToAdd - linePos : 1;
1024                gcnInsn = &defaultInsn;
1025                output.forward(bufPtr-bufStart);
1026            }
1027           
1028            // determine float literal type to display
1029            const FloatLitType displayFloatLits = 
1030                    ((disassembler.getFlags()&DISASM_FLOATLITS) != 0) ?
1031                    (((gcnInsn->mode & GCN_LITMASK) == GCN_FLOATLIT) ? FLTLIT_F32 :
1032                    ((gcnInsn->mode & GCN_LITMASK) == GCN_F16LIT) ? FLTLIT_F16 :
1033                     FLTLIT_NONE) : FLTLIT_NONE;
1034           
1035            // print instruction in correct encoding
1036            switch(gcnEncoding)
1037            {
1038                case GCNENC_SOPC:
1039                    GCNDisasmUtils::decodeSOPCEncoding(*this, pos, curReloc,
1040                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1041                    break;
1042                case GCNENC_SOPP:
1043                    GCNDisasmUtils::decodeSOPPEncoding(*this, spacesToAdd, curArchMask, 
1044                                 *gcnInsn, insnCode, insnCode2, pos);
1045                    break;
1046                case GCNENC_SOP1:
1047                    GCNDisasmUtils::decodeSOP1Encoding(*this, pos, curReloc,
1048                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1049                    break;
1050                case GCNENC_SOP2:
1051                    GCNDisasmUtils::decodeSOP2Encoding(*this, pos, curReloc,
1052                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1053                    break;
1054                case GCNENC_SOPK:
1055                    GCNDisasmUtils::decodeSOPKEncoding(*this, pos, curReloc,
1056                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1057                    break;
1058                case GCNENC_SMRD:
1059                    if (isGCN124 || isGCN15)
1060                        GCNDisasmUtils::decodeSMEMEncoding(*this, spacesToAdd, curArchMask,
1061                                  *gcnInsn, insnCode, insnCode2);
1062                    else
1063                        GCNDisasmUtils::decodeSMRDEncoding(*this, pos, curReloc,
1064                                spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1065                    break;
1066                case GCNENC_VOPC:
1067                    GCNDisasmUtils::decodeVOPCEncoding(*this, pos, curReloc, spacesToAdd,
1068                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits,
1069                           disassembler.getFlags());
1070                    break;
1071                case GCNENC_VOP1:
1072                    GCNDisasmUtils::decodeVOP1Encoding(*this, pos, curReloc, spacesToAdd,
1073                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
1074                    break;
1075                case GCNENC_VOP2:
1076                    GCNDisasmUtils::decodeVOP2Encoding(*this, pos, curReloc, spacesToAdd,
1077                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits,
1078                           disassembler.getFlags());
1079                    break;
1080                case GCNENC_VOP3A:
1081                    GCNDisasmUtils::decodeVOP3Encoding(*this, pos, curReloc,
1082                            spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2,
1083                            insnCode3, displayFloatLits, disassembler.getFlags());
1084                    break;
1085                case GCNENC_VOP3P: {
1086                    GCNInstruction newInsn = *gcnInsn;
1087                    newInsn.encoding = GCNENC_VOP3A;
1088                    newInsn.mode |= GCN_VOP3_VOP3P;
1089                    GCNDisasmUtils::decodeVOP3Encoding(*this, pos, curReloc,
1090                            spacesToAdd, curArchMask, newInsn, insnCode, insnCode2,
1091                            insnCode3, displayFloatLits, disassembler.getFlags());
1092                    break;
1093                }
1094                case GCNENC_VINTRP:
1095                    GCNDisasmUtils::decodeVINTRPEncoding(*this, spacesToAdd, curArchMask,
1096                                 *gcnInsn, insnCode);
1097                    break;
1098                case GCNENC_DS:
1099                    GCNDisasmUtils::decodeDSEncoding(*this, spacesToAdd, curArchMask,
1100                                 *gcnInsn, insnCode, insnCode2);
1101                    break;
1102                case GCNENC_MUBUF:
1103                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
1104                                 *gcnInsn, insnCode, insnCode2);
1105                    break;
1106                case GCNENC_MTBUF:
1107                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
1108                                 *gcnInsn, insnCode, insnCode2);
1109                    break;
1110                case GCNENC_MIMG:
1111                    if (!isGCN15)
1112                        GCNDisasmUtils::decodeMIMGEncoding(*this, spacesToAdd, curArchMask,
1113                                    *gcnInsn, insnCode, insnCode2);
1114                    else
1115                        GCNDisasmUtils::decodeMIMGEncodingGFX10(*this, spacesToAdd,
1116                                    curArchMask, *gcnInsn, insnCode, insnCode2, insnCode3,
1117                                    insnCode4, insnCode5);
1118                    break;
1119                case GCNENC_EXP:
1120                    GCNDisasmUtils::decodeEXPEncoding(*this, spacesToAdd, curArchMask,
1121                                 *gcnInsn, insnCode, insnCode2);
1122                    break;
1123                case GCNENC_FLAT:
1124                    GCNDisasmUtils::decodeFLATEncoding(*this, spacesToAdd, curArchMask,
1125                                 *gcnInsn, insnCode, insnCode2);
1126                    break;
1127                default:
1128                    break;
1129            }
1130        }
1131        output.put('\n');
1132    }
1133    if (!dontPrintLabelsAfterCode)
1134        writeLabelsToEnd(codeWordsNum<<2, curLabel, curNamedLabel);
1135    output.flush();
1136    disassembler.getOutput().flush();
1137}
Note: See TracBrowser for help on using the repository browser.