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

Last change on this file since 4877 was 4877, checked in by matszpk, 14 months ago

CLRadeonExtender: GCN: Fixed syntax for S_SUBVECTOR_LOOP_BEGIN and S_SUBVECTOR_LOOP_END.

File size: 48.3 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 ((!isGCN12 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
398                    (isGCN12 && gcnSize12Table[encPart]))
399                    pos++;
400                if (isGCN15 && (encPart==3 || encPart==5))
401                {
402                    // include VOP3 literal
403                    const uint32_t insnCode2 = ULEV(codeWords[pos]);
404                    if ((insnCode2 & 0x1ff) == 0xff || ((insnCode2>>9) & 0x1ff) == 0xff ||
405                        ((insnCode2>>18) & 0x1ff) == 0xff)
406                        pos++;
407                }
408            }
409        }
410        else
411        {
412            uint32_t src0 = (insnCode&0x1ff);
413            // some vector instructions
414            if ((insnCode & 0x7e000000U) == 0x7c000000U)
415            {
416                // VOPC
417                if (src0 == 0xff || // literal
418                    // SDWA, DPP
419                    (isGCN12 && (src0 == 0xf9 || src0 == 0xfa)) ||
420                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
421                    pos++;
422            }
423            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
424            {
425                // VOP1
426                if (src0 == 0xff || // literal
427                    // SDWA, DPP
428                    (isGCN12 && (src0 == 0xf9 || src0 == 0xfa)) ||
429                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
430                    pos++;
431            }
432            else
433            {
434                // VOP2
435                const cxuint opcode = (insnCode >> 25)&0x3f;
436                if ((!isGCN12 && (opcode == 32 || opcode == 33)) ||
437                    (isGCN12 && !isGCN15 && (opcode == 23 || opcode == 24 ||
438                    opcode == 36 || opcode == 37)) ||
439                    (isGCN15 && (opcode == 32 || opcode == 33 || // V_MADMK and V_MADAK
440                        opcode == 44 || opcode == 45 || // V_FMAMK_F32, V_FMAAK_F32
441                        opcode == 55 || opcode == 56))) // V_FMAMK_F16, V_FMAAK_F16
442                    pos++;  // inline 32-bit constant
443                else if (src0 == 0xff || // literal
444                    // SDWA, DPP
445                    (isGCN12 && (src0 == 0xf9 || src0 == 0xfa)) ||
446                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
447                    pos++;  // literal
448            }
449        }
450    }
451   
452    instrOutOfCode = (pos != codeWordsNum);
453}
454
455static const cxbyte gcnEncoding11Table[16] =
456{
457    GCNENC_SMRD, // 0000
458    GCNENC_SMRD, // 0001
459    GCNENC_VINTRP, // 0010
460    GCNENC_NONE, // 0011 - illegal
461    GCNENC_VOP3A, // 0100
462    GCNENC_NONE, // 0101 - illegal
463    GCNENC_DS,   // 0110
464    GCNENC_FLAT, // 0111
465    GCNENC_MUBUF, // 1000
466    GCNENC_NONE,  // 1001 - illegal
467    GCNENC_MTBUF, // 1010
468    GCNENC_NONE,  // 1011 - illegal
469    GCNENC_MIMG,  // 1100
470    GCNENC_NONE,  // 1101 - illegal
471    GCNENC_EXP,   // 1110
472    GCNENC_NONE   // 1111 - illegal
473};
474
475static const cxbyte gcnEncoding12Table[16] =
476{
477    GCNENC_SMEM, // 0000
478    GCNENC_EXP, // 0001
479    GCNENC_NONE, // 0010 - illegal
480    GCNENC_NONE, // 0011 - illegal
481    GCNENC_VOP3A, // 0100
482    GCNENC_VINTRP, // 0101
483    GCNENC_DS,   // 0110
484    GCNENC_FLAT, // 0111
485    GCNENC_MUBUF, // 1000
486    GCNENC_NONE,  // 1001 - illegal
487    GCNENC_MTBUF, // 1010
488    GCNENC_NONE,  // 1011 - illegal
489    GCNENC_MIMG,  // 1100
490    GCNENC_NONE,  // 1101 - illegal
491    GCNENC_NONE,  // 1110 - illegal
492    GCNENC_NONE   // 1111 - illegal
493};
494
495static const cxbyte gcnEncoding15Table[16] =
496{
497    GCNENC_NONE, // 0000
498    GCNENC_NONE, // 0001
499    GCNENC_VINTRP, // 0010
500    GCNENC_VOP3P, // 0011
501    GCNENC_NONE, // 0100
502    GCNENC_VOP3A, // 0101
503    GCNENC_DS,   // 0110
504    GCNENC_FLAT, // 0111
505    GCNENC_MUBUF, // 1000
506    GCNENC_NONE, // 1001 - illegal
507    GCNENC_MTBUF, // 1010
508    GCNENC_NONE,  // 1011 - illegal
509    GCNENC_MIMG,  // 1100
510    GCNENC_SMEM,  // 1101
511    GCNENC_EXP,   // 1110
512    GCNENC_NONE   // 1111 - illegal
513};
514
515
516struct CLRX_INTERNAL GCNEncodingOpcodeBits
517{
518    cxbyte bitPos;
519    cxbyte bits;
520    cxbyte bitPos2;
521    cxbyte bits2;
522};
523
524// table of opcode positions in encoding (GCN1.0/1.1)
525static const GCNEncodingOpcodeBits gcnEncodingOpcodeTable[GCNENC_MAXVAL+1] =
526{
527    { 0, 0 },
528    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
529    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
530    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
531    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
532    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
533    { 22, 6 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
534    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
535    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
536    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
537    { 17, 9 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
538    { 17, 9 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
539    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
540    { 18, 8 }, /* GCNENC_DS, opcode = (8bit)<<18 */
541    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
542    { 16, 3 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
543    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
544    { 0, 0 }, /* GCNENC_EXP, opcode = none */
545    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
546};
547
548// table of opcode positions in encoding (GCN1.2/1.4)
549static const GCNEncodingOpcodeBits gcnEncodingOpcode12Table[GCNENC_MAXVAL+1] =
550{
551    { 0, 0 },
552    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
553    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
554    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
555    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
556    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
557    { 18, 8 }, /* GCNENC_SMEM, opcode = (8bit)<<18 */
558    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
559    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
560    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
561    { 16, 10 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 */
562    { 16, 10 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 */
563    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
564    { 17, 8 }, /* GCNENC_DS, opcode = (8bit)<<17 */
565    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
566    { 15, 4 }, /* GCNENC_MTBUF, opcode = (4bit)<<15 */
567    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
568    { 0, 0 }, /* GCNENC_EXP, opcode = none */
569    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
570};
571
572// table of opcode positions in encoding (GCN1.5)
573static const GCNEncodingOpcodeBits gcnEncodingOpcode15Table[GCNENC_MAXVAL+2] =
574{
575    { 0, 0 },
576    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
577    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
578    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
579    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
580    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
581    { 18, 8 }, /* GCNENC_SMEM, opcode = (8bit)<<18 */
582    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
583    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
584    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
585    { 16, 10 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 */
586    { 16, 10 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 */
587    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
588    { 18, 8 }, /* GCNENC_DS, opcode = (8bit)<<18 */
589    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
590    { 16, 3, 53, 1 }, /* GCNENC_MTBUF, opcode = (4bit)<<15 */ // 53-bit opcode
591    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
592    { 0, 0 }, /* GCNENC_EXP, opcode = none */
593    { 18, 7 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
594    { 16, 7 } /* GCNENC_VOP3P, opcode = (7bit)<<16 */
595};
596
597/* main routine */
598
599void GCNDisassembler::disassemble()
600{
601    // select current label and reloc to first
602    LabelIter curLabel = std::lower_bound(labels.begin(), labels.end(), labelStartOffset);
603    RelocIter curReloc = std::lower_bound(relocations.begin(), relocations.end(),
604        std::make_pair(startOffset, Relocation()),
605          [](const std::pair<size_t,Relocation>& a, const std::pair<size_t, Relocation>& b)
606          { return a.first < b.first; });
607    NamedLabelIter curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
608        std::make_pair(labelStartOffset, CString()),
609          [](const std::pair<size_t,CString>& a, const std::pair<size_t, CString>& b)
610          { return a.first < b.first; });
611   
612    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
613
614    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
615                disassembler.getDeviceType());
616    // set up GCN indicators
617    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
618    const bool isGCN124 = (arch >= GPUArchitecture::GCN1_2);
619    const bool isGCN14 = (arch == GPUArchitecture::GCN1_4 || arch == GPUArchitecture::GCN1_4_1);
620    const bool isGCN15 = (arch == GPUArchitecture::GCN1_5 || arch >= GPUArchitecture::GCN1_5_1);
621    const GPUArchMask curArchMask = 
622            1U<<int(getGPUArchitectureFromDeviceType(disassembler.getDeviceType()));
623    const size_t codeWordsNum = (inputSize>>2);
624   
625    if ((inputSize&3) != 0)
626        output.write(64,
627           "        /* WARNING: Code size is not aligned to 4-byte word! */\n");
628    if (instrOutOfCode)
629        output.write(54, "        /* WARNING: Unfinished instruction at end! */\n");
630   
631    bool prevIsTwoWord = false;
632   
633    size_t pos = 0;
634    while (true)
635    {
636        writeLabelsToPosition(pos<<2, curLabel, curNamedLabel);
637        if (pos >= codeWordsNum)
638            break;
639       
640        const size_t oldPos = pos;
641        cxbyte gcnEncoding = GCNENC_NONE;
642        const uint32_t insnCode = ULEV(codeWords[pos++]);
643        if (insnCode == 0)
644        {
645            /* fix for GalliumCOmpute disassemblying (assembler doesn't accep
646             * with two scalar operands */
647            size_t count;
648            for (count = 1; pos < codeWordsNum && codeWords[pos]==0; count++, pos++);
649            // put to output
650            char* buf = output.reserve(40);
651            size_t bufPos = 0;
652            memcpy(buf+bufPos, ".fill ", 6);
653            bufPos += 6;
654            bufPos += itocstrCStyle(count, buf+bufPos, 20);
655            memcpy(buf+bufPos, ", 4, 0\n", 7);
656            bufPos += 7;
657            output.forward(bufPos);
658            continue;
659        }
660        uint32_t insnCode2 = 0;
661        uint32_t insnCode3 = 0;
662        uint32_t insnCode4 = 0;
663        uint32_t insnCode5 = 0;
664       
665        /* determine GCN encoding */
666        if ((insnCode & 0x80000000U) != 0)
667        {
668            if ((insnCode & 0x40000000U) == 0)
669            {
670                // SOP???
671                if  ((insnCode & 0x30000000U) == 0x30000000U)
672                {
673                    // SOP1/SOPK/SOPC/SOPP
674                    const uint32_t encPart = (insnCode & 0x0f800000U);
675                    if (encPart == 0x0e800000U)
676                    {
677                        // SOP1
678                        if ((insnCode&0xff) == 0xff) // literal
679                        {
680                            if (pos < codeWordsNum)
681                                insnCode2 = ULEV(codeWords[pos++]);
682                        }
683                        gcnEncoding = GCNENC_SOP1;
684                    }
685                    else if (encPart == 0x0f000000U)
686                    {
687                        // SOPC
688                        if ((insnCode&0xff) == 0xff ||
689                            (insnCode&0xff00) == 0xff00) // literal
690                        {
691                            if (pos < codeWordsNum)
692                                insnCode2 = ULEV(codeWords[pos++]);
693                        }
694                        gcnEncoding = GCNENC_SOPC;
695                    }
696                    else if (encPart == 0x0f800000U) // SOPP
697                        gcnEncoding = GCNENC_SOPP;
698                    else // SOPK
699                    {
700                        gcnEncoding = GCNENC_SOPK;
701                        const uint32_t opcode = ((insnCode>>23)&0x1f);
702                        if (((!isGCN124 || isGCN15) && opcode == 21) ||
703                            (isGCN124 && !isGCN15 && opcode == 20))
704                        {
705                            if (pos < codeWordsNum)
706                                insnCode2 = ULEV(codeWords[pos++]);
707                        }
708                    }
709                }
710                else
711                {
712                    // SOP2
713                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
714                    {
715                        // literal
716                        if (pos < codeWordsNum)
717                            insnCode2 = ULEV(codeWords[pos++]);
718                    }
719                    gcnEncoding = GCNENC_SOP2;
720                }
721            }
722            else
723            {
724                // SMRD and others
725                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
726                if (isGCN15)
727                {
728                    if (gcnSize15Table[encPart]==GCNENCSCH_MIMG_DWORDS)
729                    {
730                        cxuint extraDwords = ((insnCode>>1)&3) + 1;
731                        if (pos+extraDwords <= codeWordsNum)
732                        {
733                            if (extraDwords>=1)
734                                insnCode2 = ULEV(codeWords[pos]);
735                            if (extraDwords>=2)
736                                insnCode3 = ULEV(codeWords[pos+1]);
737                            if (extraDwords>=3)
738                                insnCode4 = ULEV(codeWords[pos+2]);
739                            if (extraDwords>=4)
740                                insnCode5 = ULEV(codeWords[pos+3]);
741                            pos += extraDwords;
742                        }
743                    }
744                    if (gcnSize15Table[encPart] && pos < codeWordsNum)
745                        insnCode2 = ULEV(codeWords[pos++]);
746                    if (isGCN15 && (encPart==3 || encPart==5))
747                    {
748                        // include VOP3 literal
749                        if ((insnCode2 & 0x1ff) == 0xff || ((insnCode2>>9) & 0x1ff) == 0xff ||
750                            ((insnCode2>>18) & 0x1ff) == 0xff)
751                            insnCode3 = ULEV(codeWords[pos++]);
752                    }
753                }
754                else if ((!isGCN124 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
755                    (isGCN124 && gcnSize12Table[encPart]))
756                {
757                    if (pos < codeWordsNum)
758                        insnCode2 = ULEV(codeWords[pos++]);
759                }
760                if (isGCN15)
761                    gcnEncoding = gcnEncoding15Table[encPart];
762                else if (isGCN124)
763                    gcnEncoding = gcnEncoding12Table[encPart];
764                else
765                    gcnEncoding = gcnEncoding11Table[encPart];
766                if (gcnEncoding == GCNENC_FLAT && !isGCN11 && !isGCN124)
767                    gcnEncoding = GCNENC_NONE; // illegal if not GCN1.1
768            }
769        }
770        else
771        {
772            // some vector instructions
773            const uint32_t src0 = (insnCode&0x1ff);
774            if ((insnCode & 0x7e000000U) == 0x7c000000U)
775            {
776                // VOPC
777                if (src0 == 0xff || // literal
778                    // SDWA, DPP
779                    (isGCN124 && (src0 == 0xf9 || src0 == 0xfa)) ||
780                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
781                {
782                    if (pos < codeWordsNum)
783                        insnCode2 = ULEV(codeWords[pos++]);
784                }
785                gcnEncoding = GCNENC_VOPC;
786            }
787            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
788            {
789                // VOP1
790                if (src0 == 0xff || // literal
791                    // SDWA, DPP
792                    (isGCN124 && (src0 == 0xf9 || src0 == 0xfa)) ||
793                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
794                {
795                    if (pos < codeWordsNum)
796                        insnCode2 = ULEV(codeWords[pos++]);
797                }
798                gcnEncoding = GCNENC_VOP1;
799            }
800            else
801            {
802                // VOP2
803                const cxuint opcode = (insnCode >> 25)&0x3f;
804                if ((!isGCN124 && (opcode == 32 || opcode == 33)) ||
805                    (isGCN124 && !isGCN15 && (opcode == 23 || opcode == 24 ||
806                    opcode == 36 || opcode == 37)) ||
807                    (isGCN15 && (opcode == 32 || opcode == 33 || // V_MADMK and V_MADAK
808                        opcode == 44 || opcode == 45 || // V_FMAMK_F32, V_FMAAK_F32
809                        opcode == 55 || opcode == 56))) // V_MADMK and V_MADAK
810                {
811                    if (pos < codeWordsNum)
812                        insnCode2 = ULEV(codeWords[pos++]);
813                }
814                else if (src0 == 0xff || // literal
815                    // SDWA, DDP
816                    (isGCN124 && (src0 == 0xf9 || src0 == 0xfa)) ||
817                    (isGCN15 && (src0 == 0xe9 || src0 == 0xea)))
818                {
819                    if (pos < codeWordsNum)
820                        insnCode2 = ULEV(codeWords[pos++]);
821                }
822                gcnEncoding = GCNENC_VOP2;
823            }
824        }
825       
826        prevIsTwoWord = (oldPos+2 == pos);
827       
828        if (disassembler.getFlags() & DISASM_HEXCODE)
829        {
830            char* buf = output.reserve(50);
831            size_t bufPos = 0;
832            buf[bufPos++] = '/';
833            buf[bufPos++] = '*';
834            if (disassembler.getFlags() & DISASM_CODEPOS)
835            {
836                // print code position
837                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
838                                buf+bufPos, 20, 16, 12, false);
839                buf[bufPos++] = ':';
840                buf[bufPos++] = ' ';
841            }
842            bufPos += itocstrCStyle(insnCode, buf+bufPos, 12, 16, 8, false);
843            buf[bufPos++] = ' ';
844            // if instruction is two word long
845            if (prevIsTwoWord)
846                bufPos += itocstrCStyle(insnCode2, buf+bufPos, 12, 16, 8, false);
847            else
848                bufPos += addSpacesOld(buf+bufPos, 8);
849            buf[bufPos++] = '*';
850            buf[bufPos++] = '/';
851            buf[bufPos++] = ' ';
852            output.forward(bufPos);
853        }
854        else // add spaces
855        {
856            if (disassembler.getFlags() & DISASM_CODEPOS)
857            {
858                // print only code position
859                char* buf = output.reserve(30);
860                size_t bufPos = 0;
861                buf[bufPos++] = '/';
862                buf[bufPos++] = '*';
863                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
864                                buf+bufPos, 20, 16, 12, false);
865                buf[bufPos++] = '*';
866                buf[bufPos++] = '/';
867                buf[bufPos++] = ' ';
868                output.forward(bufPos);
869            }
870            else
871            {
872                // add spaces
873                char* buf = output.reserve(8);
874                output.forward(addSpacesOld(buf, 8));
875            }
876        }
877       
878        if (isGCN15 && gcnEncoding == GCNENC_VOP3P && (insnCode & 0x3000000U)!=0)
879        {
880            // unknown encoding
881            gcnEncoding = GCNENC_NONE;
882            pos--;
883        }
884       
885        if (gcnEncoding == GCNENC_NONE)
886        {
887            // invalid encoding
888            char* buf = output.reserve(24);
889            size_t bufPos = 0;
890            buf[bufPos++] = '.';
891            buf[bufPos++] = 'i';
892            buf[bufPos++] = 'n';
893            buf[bufPos++] = 't';
894            buf[bufPos++] = ' '; 
895            bufPos += itocstrCStyle(insnCode, buf+bufPos, 11, 16);
896            output.forward(bufPos);
897        }
898        else
899        {
900            const GCNEncodingOpcodeBits* encodingOpcodeTable =
901                    (isGCN15) ? gcnEncodingOpcode15Table :
902                    ((isGCN124) ? gcnEncodingOpcode12Table : gcnEncodingOpcodeTable);
903            cxuint opcode =
904                    (insnCode>>encodingOpcodeTable[gcnEncoding].bitPos) & 
905                    ((1U<<encodingOpcodeTable[gcnEncoding].bits)-1U);
906            if (encodingOpcodeTable[gcnEncoding].bitPos2!=0)
907            {
908                // next bits in opcode
909                cxuint val = 0;
910                if (encodingOpcodeTable[gcnEncoding].bitPos2>=32)
911                    val = (insnCode2>>(encodingOpcodeTable[gcnEncoding].bitPos2-32));
912                else
913                    val = insnCode2>>(encodingOpcodeTable[gcnEncoding].bitPos2);
914                opcode |= (val&((1U<<encodingOpcodeTable[gcnEncoding].bits2)-1U)) <<
915                            encodingOpcodeTable[gcnEncoding].bits;
916            }
917           
918            /* decode instruction and put to output */
919            const GCNEncodingSpace& encSpace =
920                (isGCN15) ? gcnInstrTableByCodeSpaces[GCN_GFX10_ENCSPACE_IDX + gcnEncoding] :
921                ((isGCN124) ? gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+3 + gcnEncoding] :
922                  gcnInstrTableByCodeSpaces[gcnEncoding]);
923            const GCNInstruction* gcnInsn = gcnInstrTableByCode.get() +
924                    encSpace.offset + opcode;
925           
926            const GCNInstruction defaultInsn = { nullptr, gcnInsn->encoding, GCN_STDMODE,
927                        0, 0 };
928           
929            // try to replace by FMA_MIX for VEGA20
930            if ((curArchMask&ARCH_VEGA20) != 0 && gcnInsn->code>=928 && gcnInsn->code<=930)
931            {
932                const GCNEncodingSpace& encSpace4 =
933                    gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 + 1];
934                const GCNInstruction* thisGCNInstr =
935                        gcnInstrTableByCode.get() + encSpace4.offset + opcode;
936                if (thisGCNInstr->mnemonic != nullptr)
937                    // replace
938                    gcnInsn = thisGCNInstr;
939            }
940           
941            cxuint spacesToAdd = 16;
942            bool isIllegal = false;
943            if (!isGCN124 && gcnInsn->mnemonic != nullptr &&
944                (curArchMask & gcnInsn->archMask) == 0 &&
945                gcnEncoding == GCNENC_VOP3A)
946            {    /* new overrides (VOP3A) */
947                const GCNEncodingSpace& encSpace2 =
948                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
949                gcnInsn = gcnInstrTableByCode.get() + encSpace2.offset + opcode;
950                if (gcnInsn->mnemonic == nullptr ||
951                        (curArchMask & gcnInsn->archMask) == 0)
952                    isIllegal = true; // illegal
953            }
954            else if (isGCN14 && gcnInsn->mnemonic != nullptr &&
955                (curArchMask & gcnInsn->archMask) == 0 &&
956                (gcnEncoding == GCNENC_VOP3A || gcnEncoding == GCNENC_VOP2 ||
957                    gcnEncoding == GCNENC_VOP1))
958            {
959                /* new overrides (VOP1/VOP3A/VOP2 for GCN 1.4) */
960                const GCNEncodingSpace& encSpace4 =
961                        gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 +
962                                (gcnEncoding != GCNENC_VOP2) +
963                                (gcnEncoding == GCNENC_VOP1)];
964                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
965                if (gcnInsn->mnemonic == nullptr ||
966                        (curArchMask & gcnInsn->archMask) == 0)
967                    isIllegal = true; // illegal
968            }
969            else if (isGCN14 && gcnEncoding == GCNENC_FLAT && ((insnCode>>14)&3)!=0)
970            {
971                // GLOBAL_/SCRATCH_* instructions
972                const GCNEncodingSpace& encSpace4 =
973                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 +
974                        ((insnCode>>14)&3)-1];
975                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
976                if (gcnInsn->mnemonic == nullptr ||
977                        (curArchMask & gcnInsn->archMask) == 0)
978                    isIllegal = true; // illegal
979            }
980            else if (isGCN15 && gcnEncoding == GCNENC_FLAT && ((insnCode>>14)&3)!=0)
981            {
982                // GLOBAL_/SCRATCH_* instructions
983                const GCNEncodingSpace& encSpace4 =
984                    gcnInstrTableByCodeSpaces[GCN_GFX10_ENCSPACE_IDX + GCNENC_VOP3P +
985                        ((insnCode>>14)&3)];
986                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
987                if (gcnInsn->mnemonic == nullptr ||
988                        (curArchMask & gcnInsn->archMask) == 0)
989                    isIllegal = true; // illegal
990            }
991            else if (gcnInsn->mnemonic == nullptr ||
992                (curArchMask & gcnInsn->archMask) == 0)
993                isIllegal = true;
994           
995            if (!isIllegal)
996            {
997                // put spaces between mnemonic and operands
998                size_t k = ::strlen(gcnInsn->mnemonic);
999                output.writeString(gcnInsn->mnemonic);
1000                spacesToAdd = spacesToAdd>=k+1?spacesToAdd-k:1;
1001            }
1002            else
1003            {
1004                // print illegal instruction mnemonic
1005                char* bufStart = output.reserve(40);
1006                char* bufPtr = bufStart;
1007                if (!isGCN124 || gcnEncoding != GCNENC_SMEM)
1008                    putChars(bufPtr, gcnEncodingNames[gcnEncoding],
1009                            ::strlen(gcnEncodingNames[gcnEncoding]));
1010                else /* SMEM encoding */
1011                    putChars(bufPtr, "SMEM", 4);
1012                putChars(bufPtr, "_ill_", 5);
1013                // opcode value
1014                bufPtr += itocstrCStyle(opcode, bufPtr , 6);
1015                const size_t linePos = bufPtr-bufStart;
1016                spacesToAdd = spacesToAdd >= (linePos+1)? spacesToAdd - linePos : 1;
1017                gcnInsn = &defaultInsn;
1018                output.forward(bufPtr-bufStart);
1019            }
1020           
1021            // determine float literal type to display
1022            const FloatLitType displayFloatLits = 
1023                    ((disassembler.getFlags()&DISASM_FLOATLITS) != 0) ?
1024                    (((gcnInsn->mode & GCN_LITMASK) == GCN_FLOATLIT) ? FLTLIT_F32 :
1025                    ((gcnInsn->mode & GCN_LITMASK) == GCN_F16LIT) ? FLTLIT_F16 :
1026                     FLTLIT_NONE) : FLTLIT_NONE;
1027           
1028            // print instruction in correct encoding
1029            switch(gcnEncoding)
1030            {
1031                case GCNENC_SOPC:
1032                    GCNDisasmUtils::decodeSOPCEncoding(*this, pos, curReloc,
1033                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1034                    break;
1035                case GCNENC_SOPP:
1036                    GCNDisasmUtils::decodeSOPPEncoding(*this, spacesToAdd, curArchMask, 
1037                                 *gcnInsn, insnCode, insnCode2, pos);
1038                    break;
1039                case GCNENC_SOP1:
1040                    GCNDisasmUtils::decodeSOP1Encoding(*this, pos, curReloc,
1041                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1042                    break;
1043                case GCNENC_SOP2:
1044                    GCNDisasmUtils::decodeSOP2Encoding(*this, pos, curReloc,
1045                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1046                    break;
1047                case GCNENC_SOPK:
1048                    GCNDisasmUtils::decodeSOPKEncoding(*this, pos, curReloc,
1049                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
1050                    break;
1051                case GCNENC_SMRD:
1052                    if (isGCN124 || isGCN15)
1053                        GCNDisasmUtils::decodeSMEMEncoding(*this, spacesToAdd, curArchMask,
1054                                  *gcnInsn, insnCode, insnCode2);
1055                    else
1056                        GCNDisasmUtils::decodeSMRDEncoding(*this, spacesToAdd, curArchMask,
1057                                  *gcnInsn, insnCode);
1058                    break;
1059                case GCNENC_VOPC:
1060                    GCNDisasmUtils::decodeVOPCEncoding(*this, pos, curReloc, spacesToAdd,
1061                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits,
1062                           disassembler.getFlags());
1063                    break;
1064                case GCNENC_VOP1:
1065                    GCNDisasmUtils::decodeVOP1Encoding(*this, pos, curReloc, spacesToAdd,
1066                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
1067                    break;
1068                case GCNENC_VOP2:
1069                    GCNDisasmUtils::decodeVOP2Encoding(*this, pos, curReloc, spacesToAdd,
1070                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits,
1071                           disassembler.getFlags());
1072                    break;
1073                case GCNENC_VOP3A:
1074                    GCNDisasmUtils::decodeVOP3Encoding(*this, pos, curReloc,
1075                            spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2,
1076                            insnCode3, displayFloatLits, disassembler.getFlags());
1077                    break;
1078                case GCNENC_VOP3P: {
1079                    GCNInstruction newInsn = *gcnInsn;
1080                    newInsn.encoding = GCNENC_VOP3A;
1081                    newInsn.mode |= GCN_VOP3_VOP3P;
1082                    GCNDisasmUtils::decodeVOP3Encoding(*this, pos, curReloc,
1083                            spacesToAdd, curArchMask, newInsn, insnCode, insnCode2,
1084                            insnCode3, displayFloatLits, disassembler.getFlags());
1085                    break;
1086                }
1087                case GCNENC_VINTRP:
1088                    GCNDisasmUtils::decodeVINTRPEncoding(*this, spacesToAdd, curArchMask,
1089                                 *gcnInsn, insnCode);
1090                    break;
1091                case GCNENC_DS:
1092                    GCNDisasmUtils::decodeDSEncoding(*this, spacesToAdd, curArchMask,
1093                                 *gcnInsn, insnCode, insnCode2);
1094                    break;
1095                case GCNENC_MUBUF:
1096                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
1097                                 *gcnInsn, insnCode, insnCode2);
1098                    break;
1099                case GCNENC_MTBUF:
1100                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
1101                                 *gcnInsn, insnCode, insnCode2);
1102                    break;
1103                case GCNENC_MIMG:
1104                    if (!isGCN15)
1105                        GCNDisasmUtils::decodeMIMGEncoding(*this, spacesToAdd, curArchMask,
1106                                    *gcnInsn, insnCode, insnCode2);
1107                    else
1108                        GCNDisasmUtils::decodeMIMGEncodingGFX10(*this, spacesToAdd,
1109                                    curArchMask, *gcnInsn, insnCode, insnCode2, insnCode3,
1110                                    insnCode4, insnCode5);
1111                    break;
1112                case GCNENC_EXP:
1113                    GCNDisasmUtils::decodeEXPEncoding(*this, spacesToAdd, curArchMask,
1114                                 *gcnInsn, insnCode, insnCode2);
1115                    break;
1116                case GCNENC_FLAT:
1117                    GCNDisasmUtils::decodeFLATEncoding(*this, spacesToAdd, curArchMask,
1118                                 *gcnInsn, insnCode, insnCode2);
1119                    break;
1120                default:
1121                    break;
1122            }
1123        }
1124        output.put('\n');
1125    }
1126    if (!dontPrintLabelsAfterCode)
1127        writeLabelsToEnd(codeWordsNum<<2, curLabel, curNamedLabel);
1128    output.flush();
1129    disassembler.getOutput().flush();
1130}
Note: See TracBrowser for help on using the repository browser.