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

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

CLRadeonExtender: Change Copyright dates.

File size: 121.1 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
32namespace CLRX
33{
34
35// type of floating litera
36enum FloatLitType: cxbyte
37{
38    FLTLIT_NONE,    // none
39    FLTLIT_F32,     // single precision
40    FLTLIT_F16      // half precision
41};
42
43// GCN disassembler code in structure (this allow to access private code of
44// GCNDisassembler by these routines
45struct CLRX_INTERNAL GCNDisasmUtils
46{
47    typedef GCNDisassembler::RelocIter RelocIter;
48    static void printLiteral(GCNDisassembler& dasm, size_t codePos, RelocIter& relocIter,
49              uint32_t literal, FloatLitType floatLit, bool optional);
50    // decode GCN operand (version without literal)
51    static void decodeGCNOperandNoLit(GCNDisassembler& dasm, cxuint op, cxuint regNum,
52              char*& bufPtr, uint16_t arch, FloatLitType floatLit = FLTLIT_NONE);
53    // decodee GCN operand (include literal, can decode relocations)
54    static char* decodeGCNOperand(GCNDisassembler& dasm, size_t codePos,
55              RelocIter& relocIter, cxuint op, cxuint regNum, uint16_t arch,
56              uint32_t literal = 0, FloatLitType floatLit = FLTLIT_NONE);
57   
58    static void decodeSOPCEncoding(GCNDisassembler& dasm,
59             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
60             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
61   
62    static void decodeSOPPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
63             const GCNInstruction& gcnInsn, uint32_t insnCode,
64             uint32_t literal, size_t pos);
65   
66    static void decodeSOP1Encoding(GCNDisassembler& dasm,
67             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
68             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
69   
70    static void decodeSOP2Encoding(GCNDisassembler& dasm,
71             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
72             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
73   
74    static void decodeSOPKEncoding(GCNDisassembler& dasm,
75             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
76             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
77   
78    static void decodeSMRDEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
79             const GCNInstruction& gcnInsn, uint32_t insnCode);
80   
81    static void decodeSMEMEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
82             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
83   
84    static void decodeVOPCEncoding(GCNDisassembler& dasm,
85             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
86             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
87             FloatLitType displayFloatLits);
88   
89    static void decodeVOP1Encoding(GCNDisassembler& dasm,
90             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
91             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
92             FloatLitType displayFloatLits);
93   
94    static void decodeVOP2Encoding(GCNDisassembler& dasm,
95             size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
96             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
97             FloatLitType displayFloatLits);
98   
99    static void decodeVOP3Encoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
100             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2,
101             FloatLitType displayFloatLits);
102   
103    static void decodeVINTRPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
104             uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode);
105   
106    static void decodeDSEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
107             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
108   
109    static void decodeMUBUFEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
110            uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
111            uint32_t insnCode2);
112   
113    static void decodeMIMGEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
114             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
115   
116    static void decodeEXPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
117             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
118
119    static void printFLATAddr(cxuint flatMode, char*& bufPtr, uint32_t insnCode2);
120   
121    static void decodeFLATEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
122             const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
123};
124
125};
126
127using namespace CLRX;
128
129static OnceFlag clrxGCNDisasmOnceFlag;
130static std::unique_ptr<GCNInstruction[]> gcnInstrTableByCode = nullptr;
131
132// GCN encoding space
133struct CLRX_INTERNAL GCNEncodingSpace
134{
135    cxuint offset;  // first position instrunctions list
136    cxuint instrsNum;   // instruction list
137};
138
139// encoding names table
140static const char* gcnEncodingNames[GCNENC_MAXVAL+1] =
141{
142    "NONE", "SOPC", "SOPP", "SOP1", "SOP2", "SOPK", "SMRD", "VOPC", "VOP1", "VOP2",
143    "VOP3A", "VOP3B", "VINTRP", "DS", "MUBUF", "MTBUF", "MIMG", "EXP", "FLAT"
144};
145
146// table hold of GNC encoding regions in main instruction list
147// instruciton position is sum of encoding offset and instruction opcode
148static const GCNEncodingSpace gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3+2] =
149{
150    { 0, 0 },
151    { 0, 0x80 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
152    { 0x0080, 0x80 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
153    { 0x0100, 0x100 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
154    { 0x0200, 0x80 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
155    { 0x0280, 0x20 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
156    { 0x02a0, 0x40 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
157    { 0x02e0, 0x100 }, /* GCNENC_VOPC, opcode = (8bit)<<27 */
158    { 0x03e0, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
159    { 0x04e0, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
160    { 0x0520, 0x200 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
161    { 0x0520, 0x200 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
162    { 0x0720, 0x4 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
163    { 0x0724, 0x100 }, /* GCNENC_DS, opcode = (8bit)<<18 */
164    { 0x0824, 0x80 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
165    { 0x08a4, 0x8 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
166    { 0x08ac, 0x80 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
167    { 0x092c, 0x1 }, /* GCNENC_EXP, opcode = none */
168    { 0x092d, 0x80 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
169    { 0x09ad, 0x200 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 (GCN1.1) */
170    { 0x09ad, 0x200 },  /* GCNENC_VOP3B, opcode = (9bit)<<17 (GCN1.1) */
171    { 0x0bad, 0x0 },
172    { 0x0bad, 0x80 }, /* GCNENC_SOPC, opcode = (7bit)<<16 (GCN1.2) */
173    { 0x0c2d, 0x80 }, /* GCNENC_SOPP, opcode = (7bit)<<16 (GCN1.2) */
174    { 0x0cad, 0x100 }, /* GCNENC_SOP1, opcode = (8bit)<<8 (GCN1.2) */
175    { 0x0dad, 0x80 }, /* GCNENC_SOP2, opcode = (7bit)<<23 (GCN1.2) */
176    { 0x0e2d, 0x20 }, /* GCNENC_SOPK, opcode = (5bit)<<23 (GCN1.2) */
177    { 0x0e4d, 0x100 }, /* GCNENC_SMEM, opcode = (8bit)<<18 (GCN1.2) */
178    { 0x0f4d, 0x100 }, /* GCNENC_VOPC, opcode = (8bit)<<27 (GCN1.2) */
179    { 0x104d, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 (GCN1.2) */
180    { 0x114d, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 (GCN1.2) */
181    { 0x118d, 0x400 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 (GCN1.2) */
182    { 0x118d, 0x400 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 (GCN1.2) */
183    { 0x158d, 0x4 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 (GCN1.2) */
184    { 0x1591, 0x100 }, /* GCNENC_DS, opcode = (8bit)<<18 (GCN1.2) */
185    { 0x1691, 0x80 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 (GCN1.2) */
186    { 0x1711, 0x10 }, /* GCNENC_MTBUF, opcode = (4bit)<<16 (GCN1.2) */
187    { 0x1721, 0x80 }, /* GCNENC_MIMG, opcode = (7bit)<<18 (GCN1.2) */
188    { 0x17a1, 0x1 }, /* GCNENC_EXP, opcode = none (GCN1.2) */
189    { 0x17a2, 0x80 }, /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
190    { 0x1822, 0x40 }, /* GCNENC_VOP2, opcode = (6bit)<<25 (RXVEGA) */
191    { 0x1862, 0x400 }, /* GCNENC_VOP3B, opcode = (10bit)<<17  (RXVEGA) */
192    { 0x1c62, 0x100 }, /* GCNENC_VOP1, opcode = (8bit)<<9 (RXVEGA) */
193    { 0x1d62, 0x80 }, /* GCNENC_FLAT_SCRATCH, opcode = (8bit)<<18 (???8bit) RXVEGA */
194    { 0x1de2, 0x80 }  /* GCNENC_FLAT_GLOBAL, opcode = (8bit)<<18 (???8bit) RXVEGA */
195};
196
197// total instruction table length
198static const size_t gcnInstrTableByCodeLength = 0x1e62;
199
200// create main instruction table
201static void initializeGCNDisassembler()
202{
203    gcnInstrTableByCode.reset(new GCNInstruction[gcnInstrTableByCodeLength]);
204    for (cxuint i = 0; i < gcnInstrTableByCodeLength; i++)
205    {
206        gcnInstrTableByCode[i].mnemonic = nullptr;
207        gcnInstrTableByCode[i].mode = GCN_STDMODE;
208        // except VOP3 decoding routines ignores encoding (we can set None for encoding)
209        gcnInstrTableByCode[i].encoding = GCNENC_NONE;
210    }
211   
212    // fill up main instruction table
213    for (cxuint i = 0; gcnInstrsTable[i].mnemonic != nullptr; i++)
214    {
215        const GCNInstruction& instr = gcnInstrsTable[i];
216        const GCNEncodingSpace& encSpace = gcnInstrTableByCodeSpaces[instr.encoding];
217        if ((instr.archMask & ARCH_GCN_1_0_1) != 0)
218        {
219            if (gcnInstrTableByCode[encSpace.offset + instr.code].mnemonic == nullptr)
220                gcnInstrTableByCode[encSpace.offset + instr.code] = instr;
221            else if((instr.archMask & ARCH_RX2X0) != 0)
222            {
223                /* otherwise we for GCN1.1 */
224                const GCNEncodingSpace& encSpace2 =
225                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
226                gcnInstrTableByCode[encSpace2.offset + instr.code] = instr;
227            }
228            // otherwise we ignore this entry
229        }
230        if ((instr.archMask & ARCH_GCN_1_2_4) != 0)
231        {
232            // for GCN 1.2/1.4
233            const GCNEncodingSpace& encSpace3 = gcnInstrTableByCodeSpaces[
234                        GCNENC_MAXVAL+3+instr.encoding];
235            if (gcnInstrTableByCode[encSpace3.offset + instr.code].mnemonic == nullptr)
236                gcnInstrTableByCode[encSpace3.offset + instr.code] = instr;
237            else if((instr.archMask & ARCH_RXVEGA) != 0 &&
238                (instr.encoding == GCNENC_VOP2 || instr.encoding == GCNENC_VOP1 ||
239                instr.encoding == GCNENC_VOP3A || instr.encoding == GCNENC_VOP3B))
240            {
241                /* otherwise we for GCN1.4 */
242                const bool encNoVOP2 = instr.encoding != GCNENC_VOP2;
243                const bool encVOP1 = instr.encoding == GCNENC_VOP1;
244                // choose FLAT_GLOBAL or FLAT_SCRATCH space
245                const GCNEncodingSpace& encSpace4 =
246                    gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 + encNoVOP2 + encVOP1];
247                gcnInstrTableByCode[encSpace4.offset + instr.code] = instr;
248            }
249            else if((instr.archMask & ARCH_RXVEGA) != 0 &&
250                instr.encoding == GCNENC_FLAT && (instr.mode & GCN_FLAT_MODEMASK) != 0)
251            {
252                /* FLAT SCRATCH and GLOBAL instructions */
253                const cxuint encFlatMode = (instr.mode & GCN_FLAT_MODEMASK)-1;
254                const GCNEncodingSpace& encSpace4 =
255                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 + encFlatMode];
256                gcnInstrTableByCode[encSpace4.offset + instr.code] = instr;
257            }
258            // otherwise we ignore this entry
259        }
260    }
261}
262
263GCNDisassembler::GCNDisassembler(Disassembler& disassembler)
264        : ISADisassembler(disassembler), instrOutOfCode(false)
265{
266    callOnce(clrxGCNDisasmOnceFlag, initializeGCNDisassembler);
267}
268
269GCNDisassembler::~GCNDisassembler()
270{ }
271
272// gcn encoding sizes table: true - if 8 byte encoding, false - 4 byte encoding
273// for GCN1.0/1.1
274static const bool gcnSize11Table[16] =
275{
276    false, // GCNENC_SMRD, // 0000
277    false, // GCNENC_SMRD, // 0001
278    false, // GCNENC_VINTRP, // 0010
279    false, // GCNENC_NONE, // 0011 - illegal
280    true,  // GCNENC_VOP3A, // 0100
281    false, // GCNENC_NONE, // 0101 - illegal
282    true,  // GCNENC_DS,   // 0110
283    true,  // GCNENC_FLAT, // 0111
284    true,  // GCNENC_MUBUF, // 1000
285    false, // GCNENC_NONE,  // 1001 - illegal
286    true,  // GCNENC_MTBUF, // 1010
287    false, // GCNENC_NONE,  // 1011 - illegal
288    true,  // GCNENC_MIMG,  // 1100
289    false, // GCNENC_NONE,  // 1101 - illegal
290    true,  // GCNENC_EXP,   // 1110
291    false // GCNENC_NONE   // 1111 - illegal
292};
293
294// for GCN1.2/1.4
295static const bool gcnSize12Table[16] =
296{
297    true,  // GCNENC_SMEM, // 0000
298    true,  // GCNENC_EXP, // 0001
299    false, // GCNENC_NONE, // 0010 - illegal
300    false, // GCNENC_NONE, // 0011 - illegal
301    true,  // GCNENC_VOP3A, // 0100
302    false, // GCNENC_VINTRP, // 0101
303    true,  // GCNENC_DS,   // 0110
304    true,  // GCNENC_FLAT, // 0111
305    true,  // GCNENC_MUBUF, // 1000
306    false, // GCNENC_NONE,  // 1001 - illegal
307    true,  // GCNENC_MTBUF, // 1010
308    false, // GCNENC_NONE,  // 1011 - illegal
309    true,  // GCNENC_MIMG,  // 1100
310    false, // GCNENC_NONE,  // 1101 - illegal
311    false, // GCNENC_NONE,  // 1110 - illegal
312    false // GCNENC_NONE   // 1111 - illegal
313};
314
315void GCNDisassembler::analyzeBeforeDisassemble()
316{
317    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
318    const size_t codeWordsNum = (inputSize>>2);
319
320    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
321                disassembler.getDeviceType());
322    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
323    const bool isGCN12 = (arch >= GPUArchitecture::GCN1_2);
324    const bool isGCN14 = (arch == GPUArchitecture::GCN1_4);
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                            labels.push_back(startOffset +
371                                    ((pos+int16_t(insnCode&0xffff)+1)<<2));
372                        else if ((!isGCN12 && opcode == 21) ||
373                            (isGCN12 && opcode == 20))
374                            pos++; // additional literal
375                    }
376                }
377                else
378                {
379                    // SOP2
380                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
381                        pos++;  // literal
382                }
383            }
384            else
385            {
386                // SMRD and others
387                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
388                if ((!isGCN12 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
389                    (isGCN12 && gcnSize12Table[encPart]))
390                    pos++;
391            }
392        }
393        else
394        {
395            // some vector instructions
396            if ((insnCode & 0x7e000000U) == 0x7c000000U)
397            {
398                // VOPC
399                if ((insnCode&0x1ff) == 0xff || // literal
400                    // SDWA, DDP
401                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
402                    pos++;
403            }
404            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
405            {
406                // VOP1
407                if ((insnCode&0x1ff) == 0xff || // literal
408                    // SDWA, DDP
409                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
410                    pos++;
411            }
412            else
413            {
414                // VOP2
415                const cxuint opcode = (insnCode >> 25)&0x3f;
416                if ((!isGCN12 && (opcode == 32 || opcode == 33)) ||
417                    (isGCN12 && (opcode == 23 || opcode == 24 ||
418                    opcode == 36 || opcode == 37))) // V_MADMK and V_MADAK
419                    pos++;  // inline 32-bit constant
420                else if ((insnCode&0x1ff) == 0xff || // literal
421                    // SDWA, DDP
422                    (isGCN12 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
423                    pos++;  // literal
424            }
425        }
426    }
427   
428    instrOutOfCode = (pos != codeWordsNum);
429}
430
431static const cxbyte gcnEncoding11Table[16] =
432{
433    GCNENC_SMRD, // 0000
434    GCNENC_SMRD, // 0001
435    GCNENC_VINTRP, // 0010
436    GCNENC_NONE, // 0011 - illegal
437    GCNENC_VOP3A, // 0100
438    GCNENC_NONE, // 0101 - illegal
439    GCNENC_DS,   // 0110
440    GCNENC_FLAT, // 0111
441    GCNENC_MUBUF, // 1000
442    GCNENC_NONE,  // 1001 - illegal
443    GCNENC_MTBUF, // 1010
444    GCNENC_NONE,  // 1011 - illegal
445    GCNENC_MIMG,  // 1100
446    GCNENC_NONE,  // 1101 - illegal
447    GCNENC_EXP,   // 1110
448    GCNENC_NONE   // 1111 - illegal
449};
450
451static const cxbyte gcnEncoding12Table[16] =
452{
453    GCNENC_SMEM, // 0000
454    GCNENC_EXP, // 0001
455    GCNENC_NONE, // 0010 - illegal
456    GCNENC_NONE, // 0011 - illegal
457    GCNENC_VOP3A, // 0100
458    GCNENC_VINTRP, // 0101
459    GCNENC_DS,   // 0110
460    GCNENC_FLAT, // 0111
461    GCNENC_MUBUF, // 1000
462    GCNENC_NONE,  // 1001 - illegal
463    GCNENC_MTBUF, // 1010
464    GCNENC_NONE,  // 1011 - illegal
465    GCNENC_MIMG,  // 1100
466    GCNENC_NONE,  // 1101 - illegal
467    GCNENC_NONE,  // 1110 - illegal
468    GCNENC_NONE   // 1111 - illegal
469};
470
471
472struct CLRX_INTERNAL GCNEncodingOpcodeBits
473{
474    cxbyte bitPos;
475    cxbyte bits;
476};
477
478// table of opcode positions in encoding (GCN1.0/1.1)
479static const GCNEncodingOpcodeBits gcnEncodingOpcodeTable[GCNENC_MAXVAL+1] =
480{
481    { 0, 0 },
482    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
483    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
484    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
485    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
486    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
487    { 22, 6 }, /* GCNENC_SMRD, opcode = (6bit)<<22 */
488    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
489    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
490    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
491    { 17, 9 }, /* GCNENC_VOP3A, opcode = (9bit)<<17 */
492    { 17, 9 }, /* GCNENC_VOP3B, opcode = (9bit)<<17 */
493    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
494    { 18, 8 }, /* GCNENC_DS, opcode = (8bit)<<18 */
495    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
496    { 16, 3 }, /* GCNENC_MTBUF, opcode = (3bit)<<16 */
497    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
498    { 0, 0 }, /* GCNENC_EXP, opcode = none */
499    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
500};
501
502// table of opcode positions in encoding (GCN1.2/1.4)
503static const GCNEncodingOpcodeBits gcnEncodingOpcode12Table[GCNENC_MAXVAL+1] =
504{
505    { 0, 0 },
506    { 16, 7 }, /* GCNENC_SOPC, opcode = (7bit)<<16 */
507    { 16, 7 }, /* GCNENC_SOPP, opcode = (7bit)<<16 */
508    { 8, 8 }, /* GCNENC_SOP1, opcode = (8bit)<<8 */
509    { 23, 7 }, /* GCNENC_SOP2, opcode = (7bit)<<23 */
510    { 23, 5 }, /* GCNENC_SOPK, opcode = (5bit)<<23 */
511    { 18, 8 }, /* GCNENC_SMEM, opcode = (8bit)<<18 */
512    { 17, 8 }, /* GCNENC_VOPC, opcode = (8bit)<<17 */
513    { 9, 8 }, /* GCNENC_VOP1, opcode = (8bit)<<9 */
514    { 25, 6 }, /* GCNENC_VOP2, opcode = (6bit)<<25 */
515    { 16, 10 }, /* GCNENC_VOP3A, opcode = (10bit)<<16 */
516    { 16, 10 }, /* GCNENC_VOP3B, opcode = (10bit)<<16 */
517    { 16, 2 }, /* GCNENC_VINTRP, opcode = (2bit)<<16 */
518    { 17, 8 }, /* GCNENC_DS, opcode = (8bit)<<17 */
519    { 18, 7 }, /* GCNENC_MUBUF, opcode = (7bit)<<18 */
520    { 15, 4 }, /* GCNENC_MTBUF, opcode = (4bit)<<15 */
521    { 18, 7 }, /* GCNENC_MIMG, opcode = (7bit)<<18 */
522    { 0, 0 }, /* GCNENC_EXP, opcode = none */
523    { 18, 7 } /* GCNENC_FLAT, opcode = (8bit)<<18 (???8bit) */
524};
525
526// put chars to buffer (helper)
527static inline void putChars(char*& buf, const char* input, size_t size)
528{
529    ::memcpy(buf, input, size);
530    buf += size;
531}
532
533static const char* gcnOperandFloatTable[] =
534{
535    "0.5", "-0.5", "1.0", "-1.0", "2.0", "-2.0", "4.0", "-4.0"
536};
537
538union CLRX_INTERNAL FloatUnion
539{
540    float f;
541    uint32_t u;
542};
543
544// simple helpers for writing values: bytes, regranges
545
546static inline void putByteToBuf(cxuint op, char*& bufPtr)
547{
548    cxuint val = op;
549    if (val >= 100U)
550    {
551        cxuint digit2 = val/100U;
552        *bufPtr++ = digit2+'0';
553        val -= digit2*100U;
554    }
555    {
556        const cxuint digit1 = val/10U;
557        if (digit1 != 0 || op >= 100U)
558            *bufPtr++ = digit1 + '0';
559        *bufPtr++ = val-digit1*10U + '0';
560    }
561}
562
563static inline void putHexByteToBuf(cxuint op, char*& bufPtr)
564{
565    const cxuint digit0 = op&0xf;
566    const cxuint digit1 = (op&0xf0)>>4;
567    *bufPtr++ = '0';
568    *bufPtr++ = 'x';
569    if (digit1 != 0)
570        *bufPtr++ = (digit1<=9)?'0'+digit1:'a'+digit1-10;
571    *bufPtr++ = (digit0<=9)?'0'+digit0:'a'+digit0-10;
572}
573
574// print regranges
575static void regRanges(cxuint op, cxuint vregNum, char*& bufPtr)
576{
577    if (vregNum!=1)
578        *bufPtr++ = '[';
579    putByteToBuf(op, bufPtr);
580    if (vregNum!=1)
581    {
582        *bufPtr++ = ':';
583        op += vregNum-1;
584        if (op > 255)
585            op -= 256; // fix for VREGS
586        putByteToBuf(op, bufPtr);
587        *bufPtr++ = ']';
588    }
589}
590
591static void decodeGCNVRegOperand(cxuint op, cxuint vregNum, char*& bufPtr)
592{
593    *bufPtr++ = 'v';
594    return regRanges(op, vregNum, bufPtr);
595}
596
597/* parameters: dasm - disassembler, codePos - code position for relocation,
598 * relocIter, optional - if literal is optional (can be replaced by inline constant) */
599void GCNDisasmUtils::printLiteral(GCNDisassembler& dasm, size_t codePos,
600          RelocIter& relocIter, uint32_t literal, FloatLitType floatLit, bool optional)
601{
602    // if with relocation, just write
603    if (dasm.writeRelocation(dasm.startOffset + (codePos<<2)-4, relocIter))
604        return;
605    FastOutputBuffer& output = dasm.output;
606    char* bufStart = output.reserve(50);
607    char* bufPtr = bufStart;
608    if (optional && (int32_t(literal)<=64 && int32_t(literal)>=-16)) // use lit(...)
609    {
610        // use lit() to force correct encoding (avoid constants)
611        putChars(bufPtr, "lit(", 4);
612        bufPtr += itocstrCStyle<int32_t>(literal, bufPtr, 11, 10);
613        *bufPtr++ = ')';
614    }
615    else
616        bufPtr += itocstrCStyle(literal, bufPtr, 11, 16);
617    if (floatLit != FLTLIT_NONE)
618    {
619        // print float point (FP16 or FP32) literal in comment
620        FloatUnion fu;
621        fu.u = literal;
622        putChars(bufPtr, " /* ", 4);
623        if (floatLit == FLTLIT_F32)
624            bufPtr += ftocstrCStyle(fu.f, bufPtr, 20);
625        else
626            bufPtr += htocstrCStyle(fu.u, bufPtr, 20);
627        *bufPtr++ = (floatLit == FLTLIT_F32)?'f':'h';
628        putChars(bufPtr, " */", 3);
629    }
630    output.forward(bufPtr-bufStart);
631}
632
633void GCNDisasmUtils::decodeGCNOperandNoLit(GCNDisassembler& dasm, cxuint op,
634           cxuint regNum, char*& bufPtr, uint16_t arch, FloatLitType floatLit)
635{
636    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
637    const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
638    const cxuint maxSgprsNum = getGPUMaxRegsNumByArchMask(arch, REGTYPE_SGPR);
639    if ((op < maxSgprsNum) || (op >= 256 && op < 512))
640    {
641        // vector
642        if (op >= 256)
643        {
644            *bufPtr++ = 'v';
645            op -= 256;
646        }
647        // scalar
648        else
649            *bufPtr++ = 's';
650        regRanges(op, regNum, bufPtr);
651        return;
652    }
653   
654    const cxuint op2 = op&~1U;
655    if (op2 == 106 || (!isGCN14 && (op2 == 108 || op2 == 110)) || op2 == 126 ||
656        (op2 == 104 && (arch&ARCH_RX2X0)!=0) ||
657        ((op2 == 102 || op2 == 104) && isGCN12))
658    {
659        // if not SGPR, but other scalar registers
660        switch(op2)
661        {
662            case 102:
663                putChars(bufPtr, "flat_scratch", 12);
664                break;
665            case 104:
666                if (isGCN12) // GCN1.2
667                    putChars(bufPtr, "xnack_mask", 10);
668                else // GCN1.1
669                    putChars(bufPtr, "flat_scratch", 12);
670                break;
671            case 106:
672                // vcc
673                *bufPtr++ = 'v';
674                *bufPtr++ = 'c';
675                *bufPtr++ = 'c';
676                break;
677            case 108:
678                // tba
679                *bufPtr++ = 't';
680                *bufPtr++ = 'b';
681                *bufPtr++ = 'a';
682                break;
683            case 110:
684                // tma
685                *bufPtr++ = 't';
686                *bufPtr++ = 'm';
687                *bufPtr++ = 'a';
688                break;
689            case 126:
690                putChars(bufPtr, "exec", 4);
691                break;
692        }
693        // if full 64-bit register
694        if (regNum >= 2)
695        {
696            if (op&1) // unaligned!!
697            {
698                *bufPtr++ = '_';
699                *bufPtr++ = 'u';
700                *bufPtr++ = '!';
701            }
702            if (regNum > 2)
703                putChars(bufPtr, "&ill!", 5);
704            return;
705        }
706        // suffix _lo or _hi (like vcc_lo or vcc_hi)
707        *bufPtr++ = '_';
708        if ((op&1) == 0)
709        { *bufPtr++ = 'l'; *bufPtr++ = 'o'; }
710        else
711        { *bufPtr++ = 'h'; *bufPtr++ = 'i'; }
712        return;
713    }
714   
715    if (op == 255) // if literal
716    {
717        *bufPtr++ = '0'; // zero
718        *bufPtr++ = 'x'; // zero
719        *bufPtr++ = '0'; // zero
720        return;
721    }
722   
723    cxuint ttmpStart = (isGCN14 ? 108 : 112);
724    if (op >= ttmpStart && op < 124)
725    {
726        // print ttmp register
727        putChars(bufPtr, "ttmp", 4);
728        regRanges(op-ttmpStart, regNum, bufPtr);
729        return;
730    }
731    if (op == 124)
732    {
733        // M0 register
734        *bufPtr++ = 'm';
735        *bufPtr++ = '0';
736        if (regNum > 1)
737            putChars(bufPtr, "&ill!", 5);
738        return;
739    }
740   
741    if (op >= 128 && op <= 192)
742    {
743        // nonnegative integer constant
744        op -= 128;
745        const cxuint digit1 = op/10U;
746        if (digit1 != 0)
747            *bufPtr++ = digit1 + '0';
748        *bufPtr++ = op-digit1*10U + '0';
749        return;
750    }
751    if (op > 192 && op <= 208)
752    {
753        // negative integer constant
754        *bufPtr++ = '-';
755        if (op >= 202)
756        {
757            *bufPtr++ = '1';
758            *bufPtr++ = op-202+'0';
759        }
760        else
761            *bufPtr++ = op-192+'0';
762        return;
763    }
764   
765    Flags disasmFlags = dasm.disassembler.getFlags();
766    if (op >= 240 && op < 248)
767    {
768        const char* inOp = gcnOperandFloatTable[op-240];
769        putChars(bufPtr, inOp, ::strlen(inOp));
770        if ((disasmFlags & DISASM_BUGGYFPLIT)!=0 && floatLit==FLTLIT_F16)
771            *bufPtr++ = 's';    /* old rules of assembler */
772        return;
773    }
774   
775    if (isGCN14)
776        // special registers in GCN1.4 (VEGA)
777        switch(op)
778        {
779            case 0xeb:
780                putChars(bufPtr, "shared_base", 11);
781                return;
782            case 0xec:
783                putChars(bufPtr, "shared_limit", 12);
784                return;
785            case 0xed:
786                putChars(bufPtr, "private_base", 12);
787                return;
788            case 0xee:
789                putChars(bufPtr, "private_limit", 13);
790                return;
791            case 0xef:
792                putChars(bufPtr, "pops_exiting_wave_id", 20);
793                return;
794        }
795   
796    switch(op)
797    {
798        case 248:
799            if (isGCN12)
800            {
801                // 1/(2*PI)
802                putChars(bufPtr, "0.15915494", 10);
803                if ((disasmFlags & DISASM_BUGGYFPLIT)!=0 && floatLit==FLTLIT_F16)
804                    *bufPtr++ = 's';    /* old rules of assembler */
805                return;
806            }
807            break;
808        case 251:
809            putChars(bufPtr, "vccz", 4);
810            return;
811        case 252:
812            putChars(bufPtr, "execz", 5);
813            return;
814        case 253:
815            // scc
816            *bufPtr++ = 's';
817            *bufPtr++ = 'c';
818            *bufPtr++ = 'c';
819            return;
820        case 254:
821            // lds
822            *bufPtr++ = 'l';
823            *bufPtr++ = 'd';
824            *bufPtr++ = 's';
825            return;
826    }
827   
828    // reserved value (illegal)
829    putChars(bufPtr, "ill_", 4);
830    *bufPtr++ = '0'+op/100U;
831    *bufPtr++ = '0'+(op/10U)%10U;
832    *bufPtr++ = '0'+op%10U;
833}
834
835char* GCNDisasmUtils::decodeGCNOperand(GCNDisassembler& dasm, size_t codePos,
836              RelocIter& relocIter, cxuint op, cxuint regNum, uint16_t arch,
837              uint32_t literal, FloatLitType floatLit)
838{
839    FastOutputBuffer& output = dasm.output;
840    if (op == 255)
841    {
842        // if literal
843        printLiteral(dasm, codePos, relocIter, literal, floatLit, true);
844        return output.reserve(100);
845    }
846    char* bufStart = output.reserve(50);
847    char* bufPtr = bufStart;
848    decodeGCNOperandNoLit(dasm, op, regNum, bufPtr, arch, floatLit);
849    output.forward(bufPtr-bufStart);
850    return output.reserve(100);
851}
852
853// table of values sendmsg
854static const char* sendMsgCodeMessageTable[16] =
855{
856    "@0",
857    "interrupt",
858    "gs",
859    "gs_done",
860    "@4", "@5", "@6", "@7", "@8", "@9", "@10", "@11", "@12", "@13", "@14", "system"
861};
862
863// table of values sendmsg (GCN 1.4 VEGA)
864static const char* sendMsgCodeMessageTableVEGA[16] =
865{
866    "@0",
867    "interrupt",
868    "gs",
869    "gs_done",
870    "savewave",
871    "stall_wave_gen",
872    "halt_waves",
873    "ordered_ps_done",
874    "early_prim_dealloc",
875    "gs_alloc_req",
876    "get_doorbell",
877    "@11", "@12", "@13", "@14", "system"
878};
879
880
881static const char* sendGsOpMessageTable[4] =
882{ "nop", "cut", "emit", "emit-cut" };
883
884/* encoding routines */
885
886// add N spaces
887static void addSpaces(char*& bufPtr, cxuint spacesToAdd)
888{
889    for (cxuint k = spacesToAdd; k>0; k--)
890        *bufPtr++ = ' ';
891}
892
893// add N spaces (old style), return number
894static size_t addSpacesOld(char* bufPtr, cxuint spacesToAdd)
895{
896    for (cxuint k = spacesToAdd; k>0; k--)
897        *bufPtr++ = ' ';
898    return spacesToAdd;
899}
900
901void GCNDisasmUtils::decodeSOPCEncoding(GCNDisassembler& dasm, size_t codePos,
902         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
903         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
904{
905    FastOutputBuffer& output = dasm.output;
906    char* bufStart = output.reserve(90);
907    char* bufPtr = bufStart;
908    addSpaces(bufPtr, spacesToAdd);
909    output.forward(bufPtr-bufStart);
910   
911    // form: INSTR SRC0, SRC1
912    bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
913                     (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
914    *bufPtr++ = ',';
915    *bufPtr++ = ' ';
916    if ((gcnInsn.mode & GCN_SRC1_IMM) != 0)
917    {
918        // if immediate in SRC1
919        putHexByteToBuf((insnCode>>8)&0xff, bufPtr);
920        output.forward(bufPtr-bufStart);
921    }
922    else
923    {
924        output.forward(bufPtr-bufStart);
925        decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>8)&0xff,
926               (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal);
927    }
928}
929
930/// about label writer - label is workaround for class hermetization
931void GCNDisasmUtils::decodeSOPPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
932         uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
933         uint32_t literal, size_t pos)
934{
935    const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
936    FastOutputBuffer& output = dasm.output;
937    char* bufStart = output.reserve(70);
938    char* bufPtr = bufStart;
939    const cxuint imm16 = insnCode&0xffff;
940    switch(gcnInsn.mode&GCN_MASK1)
941    {
942        case GCN_IMM_REL:
943        {
944            // print relative address as label
945            const size_t branchPos = dasm.startOffset + ((pos + int16_t(imm16))<<2);
946            addSpaces(bufPtr, spacesToAdd);
947            output.forward(bufPtr-bufStart);
948            dasm.writeLocation(branchPos);
949            return;
950        }
951        case GCN_IMM_LOCKS:
952        {
953            bool prevLock = false;
954            addSpaces(bufPtr, spacesToAdd);
955            const bool isf7f = (!isGCN14 && imm16==0xf7f) ||
956                    (isGCN14 && imm16==0xcf7f);
957            // print vmcnt only if not highest value and if 0x[c]f7f value
958            if ((!isGCN14 && (imm16&15) != 15) ||
959                (isGCN14 && (imm16&0xc00f) != 0xc00f) || isf7f)
960            {
961                const cxuint lockCnt = isGCN14 ?
962                        ((imm16>>10)&0x30) + (imm16&15) : imm16&15;
963                putChars(bufPtr, "vmcnt(", 6);
964                // print value of lockCnt
965                const cxuint digit2 = lockCnt/10U;
966                if (lockCnt >= 10)
967                    *bufPtr++ = '0'+digit2;
968                *bufPtr++= '0' + lockCnt-digit2*10U;
969                *bufPtr++ = ')';
970                prevLock = true;
971            }
972            // print only if expcnt have not highest value (7)
973            if (((imm16>>4)&7) != 7 || isf7f)
974            {
975                if (prevLock)
976                {
977                    // print & before previous lock: vmcnt()
978                    *bufPtr++ = ' ';
979                    *bufPtr++ = '&';
980                    *bufPtr++ = ' ';
981                }
982                putChars(bufPtr, "expcnt(", 7);
983                // print value
984                *bufPtr++ = '0' + ((imm16>>4)&7);
985                *bufPtr++ = ')';
986                prevLock = true;
987            }
988            // print only if lgkmcnt have not highest value (15)
989            if (((imm16>>8)&15) != 15 || isf7f)
990            {
991                /* LGKMCNT bits is 4 (5????) */
992                const cxuint lockCnt = (imm16>>8)&15;
993                if (prevLock)
994                {
995                    // print & before previous lock: vmcnt()
996                    *bufPtr++ = ' ';
997                    *bufPtr++ = '&';
998                    *bufPtr++ = ' ';
999                }
1000                putChars(bufPtr, "lgkmcnt(", 8);
1001                const cxuint digit2 = lockCnt/10U;
1002                if (lockCnt >= 10)
1003                    *bufPtr++ = '0'+digit2;
1004                *bufPtr++= '0' + lockCnt-digit2*10U;
1005                *bufPtr++ = ')';
1006                prevLock = true;
1007            }
1008            if ((!isGCN14 && (imm16&0xf080) != 0) || (isGCN14 && (imm16&0x3080) != 0))
1009            {
1010                /* additional info about imm16 */
1011                if (prevLock)
1012                {
1013                    *bufPtr++ = ' ';
1014                    *bufPtr++ = ':';
1015                }
1016                bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
1017            }
1018            break;
1019        }
1020        case GCN_IMM_MSGS:
1021        {
1022            cxuint illMask = 0xfff0;
1023            addSpaces(bufPtr, spacesToAdd);
1024           
1025            // print sendmsg
1026            putChars(bufPtr, "sendmsg(", 8);
1027            const cxuint msgType = imm16&15;
1028            const char* msgName = (isGCN14 ? sendMsgCodeMessageTableVEGA[msgType] :
1029                    sendMsgCodeMessageTable[msgType]);
1030            cxuint minUnknownMsgType = isGCN14 ? 11 : 4;
1031            if ((arch & ARCH_RX3X0) != 0 && msgType == 4)
1032            {
1033                msgName = "savewave"; // 4 - savewave
1034                minUnknownMsgType = 5;
1035            }
1036            // put message name to buffer
1037            while (*msgName != 0)
1038                *bufPtr++ = *msgName++;
1039           
1040            // if also some arguments supplied (gsops)
1041            if ((msgType&14) == 2 || (msgType >= minUnknownMsgType && msgType <= 14) ||
1042                (imm16&0x3f0) != 0) // gs ops
1043            {
1044                *bufPtr++ = ',';
1045                *bufPtr++ = ' ';
1046                illMask = 0xfcc0; // set new illegal mask of bits
1047                const cxuint gsopId = (imm16>>4)&3;
1048                const char* gsopName = sendGsOpMessageTable[gsopId];
1049                // put gsop name to buffer
1050                while (*gsopName != 0)
1051                    *bufPtr++ = *gsopName++;
1052                if (gsopId!=0 || ((imm16>>8)&3)!=0)
1053                {
1054                    *bufPtr++ = ',';
1055                    *bufPtr++ = ' ';
1056                    // print gsop value
1057                    *bufPtr++ = '0' + ((imm16>>8)&3);
1058                }
1059            }
1060            *bufPtr++ = ')';
1061            // if some bits is not zero (illegal value)
1062            if ((imm16&illMask) != 0)
1063            {
1064                *bufPtr++ = ' ';
1065                *bufPtr++ = ':';
1066                bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
1067            }
1068            break;
1069        }
1070        case GCN_IMM_NONE:
1071            if (imm16 != 0)
1072            {
1073                addSpaces(bufPtr, spacesToAdd);
1074                bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
1075            }
1076            break;
1077        default:
1078            addSpaces(bufPtr, spacesToAdd);
1079            bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
1080            break;
1081    }
1082    output.forward(bufPtr-bufStart);
1083}
1084
1085void GCNDisasmUtils::decodeSOP1Encoding(GCNDisassembler& dasm, size_t codePos,
1086         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
1087         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
1088{
1089    FastOutputBuffer& output = dasm.output;
1090    char* bufStart = output.reserve(80);
1091    char* bufPtr = bufStart;
1092    addSpaces(bufPtr, spacesToAdd);
1093    bool isDst = (gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE;
1094    // print destination if instruction have it
1095    if (isDst)
1096    {
1097        output.forward(bufPtr-bufStart);
1098        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
1099                         (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
1100    }
1101   
1102    if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
1103    {
1104        if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
1105        {
1106            // put ',' if destination and source
1107            *bufPtr++ = ',';
1108            *bufPtr++ = ' ';
1109        }
1110        // put SRC1
1111        output.forward(bufPtr-bufStart);
1112        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
1113                         (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
1114    }
1115    else if ((insnCode&0xff) != 0)
1116    {
1117        // print value, if some are not used, but values is not default
1118        putChars(bufPtr," ssrc=", 6);
1119        bufPtr += itocstrCStyle((insnCode&0xff), bufPtr, 6, 16);
1120    }
1121    // print value, if some are not used, but values is not default
1122    if (!isDst && ((insnCode>>16)&0x7f) != 0)
1123    {
1124        putChars(bufPtr, " sdst=", 6);
1125        bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
1126    }
1127    output.forward(bufPtr-bufStart);
1128}
1129
1130void GCNDisasmUtils::decodeSOP2Encoding(GCNDisassembler& dasm, size_t codePos,
1131         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
1132         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
1133{
1134    FastOutputBuffer& output = dasm.output;
1135    char* bufStart = output.reserve(90);
1136    char* bufPtr = bufStart;
1137    addSpaces(bufPtr, spacesToAdd);
1138    if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
1139    {
1140        // print destination
1141        output.forward(bufPtr-bufStart);
1142        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
1143                         (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
1144        *bufPtr++ = ',';
1145        *bufPtr++ = ' ';
1146    }
1147    // print SRC0
1148    output.forward(bufPtr-bufStart);
1149    bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
1150                     (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
1151    *bufPtr++ = ',';
1152    *bufPtr++ = ' ';
1153    // print SRC1
1154    output.forward(bufPtr-bufStart);
1155    bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>8)&0xff,
1156                 (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal);
1157   
1158    // print value, if some are not used, but values is not default
1159    if ((gcnInsn.mode & GCN_MASK1) == GCN_DST_NONE && ((insnCode>>16)&0x7f) != 0)
1160    {
1161        putChars(bufPtr, " sdst=", 6);
1162        bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
1163    }
1164    output.forward(bufPtr-bufStart);
1165}
1166
1167// table hwreg names
1168static const char* hwregNames[20] =
1169{
1170    "@0", "mode", "status", "trapsts",
1171    "hw_id", "gpr_alloc", "lds_alloc", "ib_sts",
1172    "pc_lo", "pc_hi", "inst_dw0", "inst_dw1",
1173    "ib_dbg0", "ib_dbg1", "flush_ib", "sh_mem_bases",
1174    "sq_shader_tba_lo", "sq_shader_tba_hi",
1175    "sq_shader_tma_lo", "sq_shader_tma_hi"
1176};
1177
1178/// about label writer - label is workaround for class hermetization
1179void GCNDisasmUtils::decodeSOPKEncoding(GCNDisassembler& dasm, size_t codePos,
1180         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
1181         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
1182{
1183    FastOutputBuffer& output = dasm.output;
1184    char* bufStart = output.reserve(90);
1185    char* bufPtr = bufStart;
1186    addSpaces(bufPtr, spacesToAdd);
1187    if ((gcnInsn.mode & GCN_IMM_DST) == 0)
1188    {
1189        // if normal destination
1190        output.forward(bufPtr-bufStart);
1191        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
1192                         (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
1193        *bufPtr++ = ',';
1194        *bufPtr++ = ' ';
1195    }
1196    const cxuint imm16 = insnCode&0xffff;
1197    if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL)
1198    {
1199        // print relative address (as label)
1200        const size_t branchPos = dasm.startOffset + ((codePos + int16_t(imm16))<<2);
1201        output.forward(bufPtr-bufStart);
1202        dasm.writeLocation(branchPos);
1203        bufPtr = bufStart = output.reserve(60);
1204    }
1205    else if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_SREG)
1206    {
1207        // print hwreg()
1208        putChars(bufPtr, "hwreg(", 6);
1209        const cxuint hwregId = imm16&0x3f;
1210        cxuint hwregNamesNum = 13 + ((arch&ARCH_GCN_1_2_4)!=0);
1211        if ((arch&ARCH_RXVEGA) != 0)
1212            hwregNamesNum = 20;
1213        if (hwregId < hwregNamesNum)
1214            putChars(bufPtr, hwregNames[hwregId], ::strlen(hwregNames[hwregId]));
1215        else
1216        {
1217            // parametrized hwreg: hwreg(@0
1218            const cxuint digit2 = hwregId/10U;
1219            *bufPtr++ = '@';
1220            *bufPtr++ = '0' + digit2;
1221            *bufPtr++ = '0' + hwregId - digit2*10U;
1222        }
1223        *bufPtr++ = ',';
1224        *bufPtr++ = ' ';
1225        // start bit
1226        putByteToBuf((imm16>>6)&31, bufPtr);
1227        *bufPtr++ = ',';
1228        *bufPtr++ = ' ';
1229        // size in bits
1230        putByteToBuf(((imm16>>11)&31)+1, bufPtr);
1231        *bufPtr++ = ')';
1232    }
1233    else
1234        bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
1235   
1236    if (gcnInsn.mode & GCN_IMM_DST)
1237    {
1238        *bufPtr++ = ',';
1239        *bufPtr++ = ' ';
1240        // print value, if some are not used, but values is not default
1241        if (gcnInsn.mode & GCN_SOPK_CONST)
1242        {
1243            // for S_SETREG_IMM32_B32
1244            bufPtr += itocstrCStyle(literal, bufPtr, 11, 16);
1245            if (((insnCode>>16)&0x7f) != 0)
1246            {
1247                putChars(bufPtr, " sdst=", 6);
1248                bufPtr += itocstrCStyle((insnCode>>16)&0x7f, bufPtr, 6, 16);
1249            }
1250        }
1251        else
1252        {
1253            // for s_setreg_b32, print destination as source
1254            output.forward(bufPtr-bufStart);
1255            bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter,
1256                     (insnCode>>16)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
1257        }
1258    }
1259    output.forward(bufPtr-bufStart);
1260}
1261
1262void GCNDisasmUtils::decodeSMRDEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
1263             uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode)
1264{
1265    FastOutputBuffer& output = dasm.output;
1266    char* bufStart = output.reserve(100);
1267    char* bufPtr = bufStart;
1268    const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
1269    bool useDst = false;
1270    bool useOthers = false;
1271   
1272    bool spacesAdded = false;
1273    if (mode1 == GCN_SMRD_ONLYDST)
1274    {
1275        // print only destination
1276        addSpaces(bufPtr, spacesToAdd);
1277        decodeGCNOperandNoLit(dasm, (insnCode>>15)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
1278                         bufPtr, arch);
1279        useDst = true;
1280        spacesAdded = true;
1281    }
1282    else if (mode1 != GCN_ARG_NONE)
1283    {
1284        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
1285        addSpaces(bufPtr, spacesToAdd);
1286        // print destination (1,2,4,8 or 16 registers)
1287        decodeGCNOperandNoLit(dasm, (insnCode>>15)&0x7f, dregsNum, bufPtr, arch);
1288        *bufPtr++ = ',';
1289        *bufPtr++ = ' ';
1290        // print SBASE (base address registers) (address or resource)
1291        decodeGCNOperandNoLit(dasm, (insnCode>>8)&0x7e, (gcnInsn.mode&GCN_SBASE4)?4:2,
1292                          bufPtr, arch);
1293        *bufPtr++ = ',';
1294        *bufPtr++ = ' ';
1295        if (insnCode&0x100) // immediate value
1296            bufPtr += itocstrCStyle(insnCode&0xff, bufPtr, 11, 16);
1297        else // S register
1298            decodeGCNOperandNoLit(dasm, insnCode&0xff, 1, bufPtr, arch);
1299        // set what is printed
1300        useDst = true;
1301        useOthers = true;
1302        spacesAdded = true;
1303    }
1304   
1305    // print value, if some are not used, but values is not default
1306    if (!useDst && (insnCode & 0x3f8000U) != 0)
1307    {
1308        addSpaces(bufPtr, spacesToAdd-1);
1309        spacesAdded = true;
1310        putChars(bufPtr, " sdst=", 6);
1311        bufPtr += itocstrCStyle((insnCode>>15)&0x7f, bufPtr, 6, 16);
1312    }
1313    if (!useOthers && (insnCode & 0x7e00U)!=0)
1314    {
1315        if (!spacesAdded)
1316            addSpaces(bufPtr, spacesToAdd-1);
1317        spacesAdded = true;
1318        putChars(bufPtr, " sbase=", 7);
1319        bufPtr += itocstrCStyle((insnCode>>9)&0x3f, bufPtr, 6, 16);
1320    }
1321    if (!useOthers && (insnCode & 0xffU)!=0)
1322    {
1323        if (!spacesAdded)
1324            addSpaces(bufPtr, spacesToAdd-1);
1325        spacesAdded = true;
1326        putChars(bufPtr, " offset=", 8);
1327        bufPtr += itocstrCStyle(insnCode&0xff, bufPtr, 6, 16);
1328    }
1329    if (!useOthers && (insnCode & 0x100U)!=0)
1330    {
1331        if (!spacesAdded)
1332            addSpaces(bufPtr, spacesToAdd-1);
1333        spacesAdded = true;
1334        putChars(bufPtr, " imm=1", 6);
1335    }
1336    output.forward(bufPtr-bufStart);
1337}
1338
1339void GCNDisasmUtils::decodeSMEMEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
1340         uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
1341         uint32_t insnCode2)
1342{
1343    FastOutputBuffer& output = dasm.output;
1344    char* bufStart = output.reserve(120);
1345    char* bufPtr = bufStart;
1346    const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
1347    bool useDst = false;
1348    bool useOthers = false;
1349    bool spacesAdded = false;
1350    const bool isGCN14 = ((arch&ARCH_RXVEGA) != 0);
1351    bool printOffset = false;
1352   
1353    if (mode1 == GCN_SMRD_ONLYDST)
1354    {
1355        // print only destination
1356        addSpaces(bufPtr, spacesToAdd);
1357        decodeGCNOperandNoLit(dasm, (insnCode>>6)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
1358                         bufPtr, arch);
1359        useDst = true;
1360        spacesAdded = true;
1361    }
1362    else if (mode1 != GCN_ARG_NONE)
1363    {
1364        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
1365        addSpaces(bufPtr, spacesToAdd);
1366        if (!(mode1 & GCN_SMEM_NOSDATA)) {
1367            if (mode1 & GCN_SMEM_SDATA_IMM)
1368                // print immediate value
1369                putHexByteToBuf((insnCode>>6)&0x7f, bufPtr);
1370            else
1371                // print destination (1,2,4,8 or 16 registers)
1372                decodeGCNOperandNoLit(dasm, (insnCode>>6)&0x7f, dregsNum, bufPtr , arch);
1373            *bufPtr++ = ',';
1374            *bufPtr++ = ' ';
1375            useDst = true;
1376        }
1377        // print SBASE (base address registers) (address or resource)
1378        decodeGCNOperandNoLit(dasm, (insnCode<<1)&0x7e, (gcnInsn.mode&GCN_SBASE4)?4:2,
1379                          bufPtr, arch);
1380        *bufPtr++ = ',';
1381        *bufPtr++ = ' ';
1382        if (insnCode&0x20000) // immediate value
1383        {
1384            if (isGCN14 && (insnCode & 0x4000) != 0)
1385            {
1386                // last 8-bit in second dword
1387                decodeGCNOperandNoLit(dasm, (insnCode2>>25), 1, bufPtr , arch);
1388                printOffset = true;
1389            }
1390            else
1391            {
1392                // print SOFFSET
1393                uint32_t immMask =  isGCN14 ? 0x1fffff : 0xfffff;
1394                bufPtr += itocstrCStyle(insnCode2 & immMask, bufPtr, 11, 16);
1395            }
1396        }
1397        else // SOFFSET register
1398        {
1399            if (isGCN14 && (insnCode & 0x4000) != 0)
1400                decodeGCNOperandNoLit(dasm, insnCode2>>25, 1, bufPtr, arch);
1401            else
1402                decodeGCNOperandNoLit(dasm, insnCode2&0xff, 1, bufPtr, arch);
1403        }
1404        useOthers = true;
1405        spacesAdded = true;
1406    }
1407   
1408    if ((insnCode & 0x10000) != 0)
1409    {
1410        if (!spacesAdded)
1411            addSpaces(bufPtr, spacesToAdd-1);
1412        spacesAdded = true;
1413        // print GLC modifier
1414        putChars(bufPtr, " glc", 4);
1415    }
1416   
1417    if (isGCN14 && (insnCode & 0x8000) != 0)
1418    {
1419        if (!spacesAdded)
1420            addSpaces(bufPtr, spacesToAdd-1);
1421        spacesAdded = true;
1422        // print NV modifier
1423        putChars(bufPtr, " nv", 3);
1424    }
1425   
1426    if (printOffset)
1427    {
1428        // GCN 1.4 extra OFFSET
1429        if (!spacesAdded)
1430            addSpaces(bufPtr, spacesToAdd-1);
1431        spacesAdded = true;
1432        putChars(bufPtr, " offset:", 8);
1433        bufPtr += itocstrCStyle(insnCode2 & 0x1fffff, bufPtr, 11, 16);
1434    }
1435   
1436    // print value, if some are not used, but values is not default
1437    if (!useDst && (insnCode & 0x1fc0U) != 0)
1438    {
1439        if (!spacesAdded)
1440            addSpaces(bufPtr, spacesToAdd-1);
1441        spacesAdded = true;
1442        putChars(bufPtr, " sdata=", 7);
1443        bufPtr += itocstrCStyle((insnCode>>6)&0x7f, bufPtr, 6, 16);
1444    }
1445    if (!useOthers && (insnCode & 0x3fU)!=0)
1446    {
1447        if (!spacesAdded)
1448            addSpaces(bufPtr, spacesToAdd-1);
1449        spacesAdded = true;
1450        putChars(bufPtr, " sbase=", 7);
1451        bufPtr += itocstrCStyle(insnCode&0x3f, bufPtr, 6, 16);
1452    }
1453    if (!useOthers && insnCode2!=0)
1454    {
1455        if (!spacesAdded)
1456            addSpaces(bufPtr, spacesToAdd-1);
1457        spacesAdded = true;
1458        putChars(bufPtr, " offset=", 8);
1459        bufPtr += itocstrCStyle(insnCode2, bufPtr, 12, 16);
1460    }
1461    if (!useOthers && (insnCode & 0x20000U)!=0)
1462    {
1463        if (!spacesAdded)
1464            addSpaces(bufPtr, spacesToAdd-1);
1465        spacesAdded = true;
1466        putChars(bufPtr, " imm=1", 6);
1467    }
1468   
1469    output.forward(bufPtr-bufStart);
1470}
1471
1472// temporary structure to store operand modifiers and operand SRC0
1473struct CLRX_INTERNAL VOPExtraWordOut
1474{
1475    uint16_t src0;
1476    bool sextSrc0;
1477    bool negSrc0;
1478    bool absSrc0;
1479    bool sextSrc1;
1480    bool negSrc1;
1481    bool absSrc1;
1482    bool scalarSrc1;
1483};
1484
1485// SDWA SEL field value names
1486static const char* sdwaSelChoicesTbl[] =
1487{
1488    "byte0", "byte1", "byte2", "byte3", "word0", "word1", nullptr, "invalid"
1489};
1490
1491// SDWA UNUSED field value names
1492static const char* sdwaDstUnusedTbl[] =
1493{
1494    nullptr, "sext", "preserve", "invalid"
1495};
1496
1497/* returns mask of abs,neg,sext for src0 and src1 argument and src0 register */
1498static inline VOPExtraWordOut decodeVOPSDWAFlags(uint32_t insnCode2, uint16_t arch)
1499{
1500    const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
1501    return { uint16_t((insnCode2&0xff) +
1502        ((!isGCN14 || (insnCode2 & (1U<<23))==0) ? 256 : 0)),
1503        (insnCode2&(1U<<19))!=0, (insnCode2&(1U<<20))!=0, (insnCode2&(1U<<21))!=0,
1504        (insnCode2&(1U<<27))!=0, (insnCode2&(1U<<28))!=0, (insnCode2&(1U<<29))!=0,
1505        isGCN14 && ((insnCode2&(1U<<31))!=0) };
1506}
1507
1508// decode and print VOP SDWA encoding
1509static void decodeVOPSDWA(FastOutputBuffer& output, uint16_t arch, uint32_t insnCode2,
1510          bool src0Used, bool src1Used, bool vopc = false)
1511{
1512    char* bufStart = output.reserve(100);
1513    char* bufPtr = bufStart;
1514    const bool isGCN14 = ((arch&ARCH_RXVEGA) != 0);
1515    cxuint dstSel = 6;
1516    cxuint dstUnused = 0;
1517    if (!isGCN14 || !vopc)
1518    {
1519        // not VEGA or not VOPC
1520        dstSel = (insnCode2>>8)&7;
1521        dstUnused = (insnCode2>>11)&3;
1522    }
1523    const cxuint src0Sel = (insnCode2>>16)&7;
1524    const cxuint src1Sel = (insnCode2>>24)&7;
1525   
1526    if (!isGCN14 || !vopc)
1527    {
1528        // not VEGA or not VOPC
1529        if (isGCN14 && (insnCode2 & 0xc000U) != 0)
1530        {
1531            cxuint omod = (insnCode2>>14)&3;
1532            const char* omodStr = (omod==3)?" div:2":(omod==2)?" mul:4":" mul:2";
1533            putChars(bufPtr, omodStr, 6);
1534        }
1535        if (insnCode2 & 0x2000)
1536            putChars(bufPtr, " clamp", 6);
1537       
1538        // print dst_sel:XXXX
1539        if (dstSel != 6)
1540        {
1541            putChars(bufPtr, " dst_sel:", 9);
1542            putChars(bufPtr, sdwaSelChoicesTbl[dstSel],
1543                    ::strlen(sdwaSelChoicesTbl[dstSel]));
1544        }
1545        // print dst_unused:XXX
1546        if (dstUnused!=0)
1547        {
1548            putChars(bufPtr, " dst_unused:", 12);
1549            putChars(bufPtr, sdwaDstUnusedTbl[dstUnused],
1550                    ::strlen(sdwaDstUnusedTbl[dstUnused]));
1551        }
1552    }
1553    // print src0_sel and src1_sel if used
1554    if (src0Sel!=6 && src0Used)
1555    {
1556        putChars(bufPtr, " src0_sel:", 10);
1557        putChars(bufPtr, sdwaSelChoicesTbl[src0Sel],
1558                 ::strlen(sdwaSelChoicesTbl[src0Sel]));
1559    }
1560    if (src1Sel!=6 && src1Used)
1561    {
1562        putChars(bufPtr, " src1_sel:", 10);
1563        putChars(bufPtr, sdwaSelChoicesTbl[src1Sel],
1564                 ::strlen(sdwaSelChoicesTbl[src1Sel]));
1565    }
1566    // unused but fields
1567    if (!src0Used)
1568    {
1569        if ((insnCode2&(1U<<19))!=0)
1570            putChars(bufPtr, " sext0", 6);
1571        if ((insnCode2&(1U<<20))!=0)
1572            putChars(bufPtr, " neg0", 5);
1573        if ((insnCode2&(1U<<21))!=0)
1574            putChars(bufPtr, " abs0", 5);
1575    }
1576    if (!src1Used)
1577    {
1578        if ((insnCode2&(1U<<27))!=0)
1579            putChars(bufPtr, " sext1", 6);
1580        if ((insnCode2&(1U<<28))!=0)
1581            putChars(bufPtr, " neg1", 5);
1582        if ((insnCode2&(1U<<29))!=0)
1583            putChars(bufPtr, " abs1", 5);
1584    }
1585   
1586    // add SDWA encoding specifier at end if needed (to avoid ambiguity)
1587    if (((isGCN14 && vopc) || (dstSel==6 && dstUnused==0)) &&
1588        src0Sel==6 && (insnCode2&(1U<<19))==0 && src1Sel==6 && (insnCode2&(1U<<27))==0)
1589        putChars(bufPtr, " sdwa", 5);
1590   
1591    output.forward(bufPtr-bufStart);
1592}
1593
1594/// DPP CTRL value table (only
1595static const char* dppCtrl130Tbl[] =
1596{
1597    " wave_shl", nullptr, nullptr, nullptr,
1598    " wave_rol", nullptr, nullptr, nullptr,
1599    " wave_shr", nullptr, nullptr, nullptr,
1600    " wave_ror", nullptr, nullptr, nullptr,
1601    " row_mirror", " row_half_mirror", " row_bcast15", " row_bcast31"
1602};
1603
1604/* returns mask of abs,neg,sext for src0 and src1 argument and src0 register */
1605static inline VOPExtraWordOut decodeVOPDPPFlags(uint32_t insnCode2)
1606{
1607    return { uint16_t((insnCode2&0xff)+256),
1608        false, (insnCode2&(1U<<20))!=0, (insnCode2&(1U<<21))!=0,
1609        false, (insnCode2&(1U<<22))!=0, (insnCode2&(1U<<23))!=0, false };
1610}
1611
1612static void decodeVOPDPP(FastOutputBuffer& output, uint32_t insnCode2,
1613        bool src0Used, bool src1Used)
1614{
1615    char* bufStart = output.reserve(110);
1616    char* bufPtr = bufStart;
1617    const cxuint dppCtrl = (insnCode2>>8)&0x1ff;
1618   
1619    if (dppCtrl<256)
1620    {
1621        // print quadperm: quad_perm[A:B:C:D] A,B,C,D - 2-bit values
1622        putChars(bufPtr, " quad_perm:[", 12);
1623        *bufPtr++ = '0' + (dppCtrl&3);
1624        *bufPtr++ = ',';
1625        *bufPtr++ = '0' + ((dppCtrl>>2)&3);
1626        *bufPtr++ = ',';
1627        *bufPtr++ = '0' + ((dppCtrl>>4)&3);
1628        *bufPtr++ = ',';
1629        *bufPtr++ = '0' + ((dppCtrl>>6)&3);
1630        *bufPtr++ = ']';
1631    }
1632    else if ((dppCtrl >= 0x101 && dppCtrl <= 0x12f) && ((dppCtrl&0xf) != 0))
1633    {
1634        // row_shl, row_shr or row_ror
1635        if ((dppCtrl&0xf0) == 0)
1636            putChars(bufPtr, " row_shl:", 9);
1637        else if ((dppCtrl&0xf0) == 16)
1638            putChars(bufPtr, " row_shr:", 9);
1639        else
1640            putChars(bufPtr, " row_ror:", 9);
1641        // print shift
1642        putByteToBuf(dppCtrl&0xf, bufPtr);
1643    }
1644    else if (dppCtrl >= 0x130 && dppCtrl <= 0x143 && dppCtrl130Tbl[dppCtrl-0x130]!=nullptr)
1645        // print other dpp modifier
1646        putChars(bufPtr, dppCtrl130Tbl[dppCtrl-0x130],
1647                 ::strlen(dppCtrl130Tbl[dppCtrl-0x130]));
1648    // otherwise print value of dppctrl (illegal value)
1649    else if (dppCtrl != 0x100)
1650    {
1651        putChars(bufPtr, " dppctrl:", 9);
1652        bufPtr += itocstrCStyle(dppCtrl, bufPtr, 10, 16);
1653    }
1654   
1655    if (insnCode2 & (0x80000U)) // bound ctrl
1656        putChars(bufPtr, " bound_ctrl", 11);
1657   
1658    // print bank_mask and row_mask
1659    putChars(bufPtr, " bank_mask:", 11);
1660    putByteToBuf((insnCode2>>24)&0xf, bufPtr);
1661    putChars(bufPtr, " row_mask:", 10);
1662    putByteToBuf((insnCode2>>28)&0xf, bufPtr);
1663    // unused but fields
1664    if (!src0Used)
1665    {
1666        if ((insnCode2&(1U<<20))!=0)
1667            putChars(bufPtr, " neg0", 5);
1668        if ((insnCode2&(1U<<21))!=0)
1669            putChars(bufPtr, " abs0", 5);
1670    }
1671    if (!src1Used)
1672    {
1673        if ((insnCode2&(1U<<22))!=0)
1674            putChars(bufPtr, " neg1", 5);
1675        if ((insnCode2&(1U<<23))!=0)
1676            putChars(bufPtr, " abs1", 5);
1677    }
1678   
1679    output.forward(bufPtr-bufStart);
1680}
1681
1682void GCNDisasmUtils::decodeVOPCEncoding(GCNDisassembler& dasm, size_t codePos,
1683         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
1684         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
1685         FloatLitType displayFloatLits)
1686{
1687    FastOutputBuffer& output = dasm.output;
1688    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
1689    char* bufStart = output.reserve(120);
1690    char* bufPtr = bufStart;
1691    addSpaces(bufPtr, spacesToAdd);
1692   
1693    const cxuint src0Field = (insnCode&0x1ff);
1694    // extra flags are zeroed by default
1695    VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
1696    if ((arch & ARCH_RXVEGA) != 0 && src0Field==0xf9 && (literal & 0x8000) != 0)
1697    {
1698        // SDWAB replacement of SDST
1699        output.forward(bufPtr-bufStart);
1700        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter,
1701                            (literal>>8)&0x7f, 2, arch);
1702        *bufPtr++ = ',';
1703        *bufPtr++ = ' ';
1704    }
1705    else // just vcc
1706        putChars(bufPtr, "vcc, ", 5);
1707   
1708    if (isGCN12)
1709    {
1710        // return VOP SDWA/DPP flags for operands
1711        if (src0Field == 0xf9)
1712            extraFlags = decodeVOPSDWAFlags(literal, arch);
1713        else if (src0Field == 0xfa)
1714            extraFlags = decodeVOPDPPFlags(literal);
1715        else
1716            extraFlags.src0 = src0Field;
1717    }
1718    else
1719        extraFlags.src0 = src0Field;
1720   
1721    // apply sext(), negation and abs() if applied
1722    if (extraFlags.sextSrc0)
1723        putChars(bufPtr, "sext(", 5);
1724    if (extraFlags.negSrc0)
1725        *bufPtr++ = '-';
1726    if (extraFlags.absSrc0)
1727        putChars(bufPtr, "abs(", 4);
1728   
1729    output.forward(bufPtr-bufStart);
1730    // print SRC0
1731    bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
1732                 (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1733    // closing for abs and sext
1734    if (extraFlags.absSrc0)
1735        *bufPtr++ = ')';
1736    if (extraFlags.sextSrc0)
1737        *bufPtr++ = ')';
1738    *bufPtr++ = ',';
1739    *bufPtr++ = ' ';
1740   
1741    // apply sext(), negation and abs() if applied
1742    if (extraFlags.sextSrc1)
1743        putChars(bufPtr, "sext(", 5);
1744   
1745    if (extraFlags.negSrc1)
1746        *bufPtr++ = '-';
1747    if (extraFlags.absSrc1)
1748        putChars(bufPtr, "abs(", 4);
1749   
1750    // print SRC1
1751    decodeGCNOperandNoLit(dasm, ((insnCode>>9)&0xff) + (extraFlags.scalarSrc1 ? 0 : 256),
1752                (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr, arch);
1753    // closing for abs and sext
1754    if (extraFlags.absSrc1)
1755        *bufPtr++ = ')';
1756    if (extraFlags.sextSrc1)
1757        *bufPtr++ = ')';
1758   
1759    output.forward(bufPtr-bufStart);
1760    if (isGCN12)
1761    {
1762        // print extra SDWA/DPP modifiers
1763        if (src0Field == 0xf9)
1764            decodeVOPSDWA(output, arch, literal, true, true, true);
1765        else if (src0Field == 0xfa)
1766            decodeVOPDPP(output, literal, true, true);
1767    }
1768}
1769
1770void GCNDisasmUtils::decodeVOP1Encoding(GCNDisassembler& dasm, size_t codePos,
1771         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
1772         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
1773         FloatLitType displayFloatLits)
1774{
1775    FastOutputBuffer& output = dasm.output;
1776    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
1777    char* bufStart = output.reserve(130);
1778    char* bufPtr = bufStart;
1779   
1780    const cxuint src0Field = (insnCode&0x1ff);
1781    // extra flags are zeroed by default
1782    VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
1783   
1784    if (isGCN12)
1785    {
1786        // return extra flags from SDWA/DPP encoding
1787        if (src0Field == 0xf9)
1788            extraFlags = decodeVOPSDWAFlags(literal, arch);
1789        else if (src0Field == 0xfa)
1790            extraFlags = decodeVOPDPPFlags(literal);
1791        else
1792            extraFlags.src0 = src0Field;
1793    }
1794    else
1795        extraFlags.src0 = src0Field;
1796   
1797    bool argsUsed = true;
1798    if ((gcnInsn.mode & GCN_MASK1) != GCN_VOP_ARG_NONE)
1799    {
1800        addSpaces(bufPtr, spacesToAdd);
1801        if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_SGPR)
1802            // print DST as SGPR
1803            decodeGCNVRegOperand(((insnCode>>17)&0xff),
1804                     (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr);
1805        else
1806            // print DST as normal VGPR
1807            decodeGCNOperandNoLit(dasm, ((insnCode>>17)&0xff),
1808                          (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr, arch);
1809        *bufPtr++ = ',';
1810        *bufPtr++ = ' ';
1811        // apply sext, negation and abs if supplied
1812        if (extraFlags.sextSrc0)
1813            putChars(bufPtr, "sext(", 5);
1814       
1815        if (extraFlags.negSrc0)
1816            *bufPtr++ = '-';
1817        if (extraFlags.absSrc0)
1818            putChars(bufPtr, "abs(", 4);
1819        output.forward(bufPtr-bufStart);
1820        // print SRC0
1821        bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
1822                     (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1823        // closing sext and abs
1824        if (extraFlags.absSrc0)
1825            *bufPtr++ = ')';
1826        if (extraFlags.sextSrc0)
1827            *bufPtr++ = ')';
1828    }
1829    else if ((insnCode & 0x1fe01ffU) != 0)
1830    {
1831        // unused, but set fields
1832        addSpaces(bufPtr, spacesToAdd);
1833        if ((insnCode & 0x1fe0000U) != 0)
1834        {
1835            putChars(bufPtr, "vdst=", 5);
1836            bufPtr += itocstrCStyle((insnCode>>17)&0xff, bufPtr, 6, 16);
1837            if ((insnCode & 0x1ff) != 0)
1838                *bufPtr++ = ' ';
1839        }
1840        if ((insnCode & 0x1ff) != 0)
1841        {
1842            putChars(bufPtr, "src0=", 5);
1843            bufPtr += itocstrCStyle(insnCode&0x1ff, bufPtr, 6, 16);
1844        }
1845        argsUsed = false;
1846    }
1847    output.forward(bufPtr-bufStart);
1848    if (isGCN12)
1849    {
1850        // print extra SDWA/DPP modifiers
1851        if (src0Field == 0xf9)
1852            decodeVOPSDWA(output, arch, literal, argsUsed, false);
1853        else if (src0Field == 0xfa)
1854            decodeVOPDPP(output, literal, argsUsed, false);
1855    }
1856}
1857
1858void GCNDisasmUtils::decodeVOP2Encoding(GCNDisassembler& dasm, size_t codePos,
1859         RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
1860         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
1861         FloatLitType displayFloatLits)
1862{
1863    FastOutputBuffer& output = dasm.output;
1864    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
1865    char* bufStart = output.reserve(150);
1866    char* bufPtr = bufStart;
1867   
1868    addSpaces(bufPtr, spacesToAdd);
1869    const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
1870   
1871    const cxuint src0Field = (insnCode&0x1ff);
1872    // extra flags are zeroed by default
1873    VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
1874   
1875    if (isGCN12)
1876    {
1877        // return extra flags from SDWA/DPP encoding
1878        if (src0Field == 0xf9)
1879            extraFlags = decodeVOPSDWAFlags(literal, arch);
1880        else if (src0Field == 0xfa)
1881            extraFlags = decodeVOPDPPFlags(literal);
1882        else
1883            extraFlags.src0 = src0Field;
1884    }
1885    else
1886        extraFlags.src0 = src0Field;
1887   
1888    if (mode1 != GCN_DS1_SGPR)
1889        // print DST as SGPR
1890        decodeGCNVRegOperand(((insnCode>>17)&0xff),
1891                     (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr);
1892    else
1893        decodeGCNOperandNoLit(dasm, ((insnCode>>17)&0xff),
1894                 (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr, arch);
1895   
1896    // add VCC if V_ADD_XXX or other instruction VCC as DST
1897    if (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC)
1898        putChars(bufPtr, ", vcc", 5);
1899    *bufPtr++ = ',';
1900    *bufPtr++ = ' ';
1901    // apply sext, negation and abs if supplied
1902    if (extraFlags.sextSrc0)
1903        putChars(bufPtr, "sext(", 5);
1904    if (extraFlags.negSrc0)
1905        *bufPtr++ = '-';
1906    if (extraFlags.absSrc0)
1907        putChars(bufPtr, "abs(", 4);
1908    output.forward(bufPtr-bufStart);
1909    // print SRC0
1910    bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
1911                 (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1912    // closing sext and abs
1913    if (extraFlags.absSrc0)
1914        *bufPtr++ = ')';
1915    if (extraFlags.sextSrc0)
1916        *bufPtr++ = ')';
1917    if (mode1 == GCN_ARG1_IMM)
1918    {
1919        // extra immediate (like V_MADMK_F32)
1920        *bufPtr++ = ',';
1921        *bufPtr++ = ' ';
1922        output.forward(bufPtr-bufStart);
1923        printLiteral(dasm, codePos, relocIter, literal, displayFloatLits, false);
1924        bufStart = bufPtr = output.reserve(100);
1925    }
1926    *bufPtr++ = ',';
1927    *bufPtr++ = ' ';
1928    // apply sext, negation and abs if supplied
1929    if (extraFlags.sextSrc1)
1930        putChars(bufPtr, "sext(", 5);
1931   
1932    if (extraFlags.negSrc1)
1933        *bufPtr++ = '-';
1934    if (extraFlags.absSrc1)
1935        putChars(bufPtr, "abs(", 4);
1936    // print SRC0
1937    if (mode1 == GCN_DS1_SGPR || mode1 == GCN_SRC1_SGPR)
1938    {
1939        output.forward(bufPtr-bufStart);
1940        bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter,
1941                 ((insnCode>>9)&0xff), (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch);
1942    }
1943    else
1944        decodeGCNOperandNoLit(dasm, ((insnCode>>9)&0xff) +
1945                (extraFlags.scalarSrc1 ? 0 : 256),
1946                (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr, arch);
1947    // closing sext and abs
1948    if (extraFlags.absSrc1)
1949        *bufPtr++ = ')';
1950    if (extraFlags.sextSrc1)
1951        *bufPtr++ = ')';
1952    if (mode1 == GCN_ARG2_IMM)
1953    {
1954        // extra immediate (like V_MADAK_F32)
1955        *bufPtr++ = ',';
1956        *bufPtr++ = ' ';
1957        output.forward(bufPtr-bufStart);
1958        printLiteral(dasm, codePos, relocIter, literal, displayFloatLits, false);
1959    }
1960    else if (mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC)
1961    {
1962        // VCC like in V_CNDMASK_B32 or V_SUBB_B32
1963        putChars(bufPtr, ", vcc", 5);
1964        output.forward(bufPtr-bufStart);
1965    }
1966    else
1967        output.forward(bufPtr-bufStart);
1968    if (isGCN12)
1969    {
1970        // print extra SDWA/DPP modifiers
1971        if (src0Field == 0xf9)
1972            decodeVOPSDWA(output, arch, literal, true, true);
1973        else if (src0Field == 0xfa)
1974            decodeVOPDPP(output, literal, true, true);
1975    }
1976}
1977
1978// VINTRP param names
1979static const char* vintrpParamsTbl[] =
1980{ "p10", "p20", "p0" };
1981
1982static void decodeVINTRPParam(uint16_t p, char*& bufPtr)
1983{
1984    if (p >= 3)
1985    {
1986        putChars(bufPtr, "invalid_", 8);
1987        bufPtr += itocstrCStyle(p, bufPtr, 8);
1988    }
1989    else
1990        putChars(bufPtr, vintrpParamsTbl[p], ::strlen(vintrpParamsTbl[p]));
1991}
1992
1993void GCNDisasmUtils::decodeVOP3Encoding(GCNDisassembler& dasm, cxuint spacesToAdd,
1994         uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
1995         uint32_t insnCode2, FloatLitType displayFloatLits)
1996{
1997    FastOutputBuffer& output = dasm.output;
1998    char* bufStart = output.reserve(170);
1999    char* bufPtr = bufStart;
2000    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
2001    const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
2002    const cxuint opcode = (isGCN12) ? ((insnCode>>16)&0x3ff) : ((insnCode>>17)&0x1ff);
2003   
2004    const cxuint vdst = insnCode&0xff;
2005    const cxuint vsrc0 = insnCode2&0x1ff;
2006    const cxuint vsrc1 = (insnCode2>>9)&0x1ff;
2007    const cxuint vsrc2 = (insnCode2>>18)&0x1ff;
2008    const cxuint sdst = (insnCode>>8)&0x7f;
2009    const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
2010    const uint16_t vop3Mode = (gcnInsn.mode&GCN_VOP3_MASK2);
2011   
2012    bool vdstUsed = false;
2013    bool vsrc0Used = false;
2014    bool vsrc1Used = false;
2015    bool vsrc2Used = false;
2016    bool vsrc2CC = false;
2017    cxuint absFlags = 0;
2018    cxuint negFlags = 0;
2019   
2020    if (gcnInsn.encoding == GCNENC_VOP3A && vop3Mode != GCN_VOP3_VOP3P)
2021        absFlags = (insnCode>>8)&7;
2022    // get negation flags from insnCode (VOP3P)
2023    if (vop3Mode != GCN_VOP3_VOP3P)
2024        negFlags = (insnCode2>>29)&7;
2025   
2026    const bool is128Ops = (gcnInsn.mode&0x7000)==GCN_VOP3_DS2_128;
2027   
2028    if (mode1 != GCN_VOP_ARG_NONE)
2029    {
2030        addSpaces(bufPtr, spacesToAdd);
2031       
2032        if (opcode < 256 || (gcnInsn.mode&GCN_VOP3_DST_SGPR)!=0)
2033            /* if compares (print DST as SDST) */
2034            decodeGCNOperandNoLit(dasm, vdst, ((gcnInsn.mode&GCN_VOP3_DST_SGPR)==0)?2:1,
2035                              bufPtr, arch);
2036        else /* regular instruction */
2037            // for V_MQSAD_U32 SRC2 is 128-bit
2038            decodeGCNVRegOperand(vdst, (is128Ops) ? 4 : 
2039                                 ((gcnInsn.mode&GCN_REG_DST_64)?2:1), bufPtr);
2040       
2041        if (gcnInsn.encoding == GCNENC_VOP3B &&
2042            (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC || mode1 == GCN_DST_VCC_VSRC2 ||
2043             mode1 == GCN_S0EQS12)) /* VOP3b */
2044        {
2045            // print SDST operand (VOP3B)
2046            *bufPtr++ = ',';
2047            *bufPtr++ = ' ';
2048            decodeGCNOperandNoLit(dasm, ((insnCode>>8)&0x7f), 2, bufPtr, arch);
2049        }
2050        *bufPtr++ = ',';
2051        *bufPtr++ = ' ';
2052        if (vop3Mode != GCN_VOP3_VINTRP)
2053        {
2054            // print negation or abs if supplied
2055            if (negFlags & 1)
2056                *bufPtr++ = '-';
2057            if (absFlags & 1)
2058                putChars(bufPtr, "abs(", 4);
2059            // print VSRC0
2060            decodeGCNOperandNoLit(dasm, vsrc0, (gcnInsn.mode&GCN_REG_SRC0_64)?2:1,
2061                                   bufPtr, arch, displayFloatLits);
2062            // closing abs
2063            if (absFlags & 1)
2064                *bufPtr++ = ')';
2065            vsrc0Used = true;
2066        }
2067       
2068        if (vop3Mode == GCN_VOP3_VINTRP)
2069        {
2070            // print negation or abs if supplied
2071            if (negFlags & 2)
2072                *bufPtr++ = '-';
2073            if (absFlags & 2)
2074                putChars(bufPtr, "abs(", 4);
2075            if (mode1 == GCN_P0_P10_P20)
2076                // VINTRP param
2077                decodeVINTRPParam(vsrc1, bufPtr);
2078            else
2079                // print VSRC1
2080                decodeGCNOperandNoLit(dasm, vsrc1, 1, bufPtr, arch, displayFloatLits);
2081            if (absFlags & 2)
2082                *bufPtr++ = ')';
2083            // print VINTRP attr
2084            putChars(bufPtr, ", attr", 6);
2085            const cxuint attr = vsrc0&63;
2086            putByteToBuf(attr, bufPtr);
2087            *bufPtr++ = '.';
2088            *bufPtr++ = "xyzw"[((vsrc0>>6)&3)]; // attrchannel
2089           
2090            if ((gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2)
2091            {
2092                *bufPtr++ = ',';
2093                *bufPtr++ = ' ';
2094                // print abs and negation for VSRC2
2095                if (negFlags & 4)
2096                    *bufPtr++ = '-';
2097                if (absFlags & 4)
2098                    putChars(bufPtr, "abs(", 4);
2099                // print VSRC2
2100                decodeGCNOperandNoLit(dasm, vsrc2, 1, bufPtr, arch, displayFloatLits);
2101                if (absFlags & 4)
2102                    *bufPtr++ = ')';
2103                vsrc2Used = true;
2104            }
2105           
2106            if (vsrc0 & 0x100)
2107                putChars(bufPtr, " high", 5);
2108            vsrc0Used = true;
2109            vsrc1Used = true;
2110        }
2111        else if (mode1 != GCN_SRC12_NONE)
2112        {
2113            *bufPtr++ = ',';
2114            *bufPtr++ = ' ';
2115            // print abs and negation for VSRC1
2116            if (negFlags & 2)
2117                *bufPtr++ = '-';
2118            if (absFlags & 2)
2119                putChars(bufPtr, "abs(", 4);
2120            // print VSRC1
2121            decodeGCNOperandNoLit(dasm, vsrc1, (gcnInsn.mode&GCN_REG_SRC1_64)?2:1,
2122                      bufPtr, arch, displayFloatLits);
2123            if (absFlags & 2)
2124                *bufPtr++ = ')';
2125            /* GCN_DST_VCC - only sdst is used, no vsrc2 */
2126            if (mode1 != GCN_SRC2_NONE && mode1 != GCN_DST_VCC && opcode >= 256)
2127            {
2128                *bufPtr++ = ',';
2129                *bufPtr++ = ' ';
2130               
2131                if (mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC)
2132                {
2133                    decodeGCNOperandNoLit(dasm, vsrc2, 2, bufPtr, arch);
2134                    vsrc2CC = true;
2135                }
2136                else
2137                {
2138                    // print abs and negation for VSRC2
2139                    if (negFlags & 4)
2140                        *bufPtr++ = '-';
2141                    if (absFlags & 4)
2142                        putChars(bufPtr, "abs(", 4);
2143                    // for V_MQSAD_U32 SRC2 is 128-bit
2144                    // print VSRC2
2145                    decodeGCNOperandNoLit(dasm, vsrc2, is128Ops ? 4 :
2146                                (gcnInsn.mode&GCN_REG_SRC2_64)?2:1,
2147                                 bufPtr, arch, displayFloatLits);
2148                    if (absFlags & 4)
2149                        *bufPtr++ = ')';
2150                }
2151                vsrc2Used = true;
2152            }
2153            vsrc1Used = true;
2154        }
2155       
2156        vdstUsed = true;
2157    }
2158    else
2159        addSpaces(bufPtr, spacesToAdd-1);
2160   
2161    uint32_t opselBaseMask = 0;
2162    uint32_t opselMask = 1;
2163    uint32_t opsel = 0;
2164    if (isGCN14 && gcnInsn.encoding != GCNENC_VOP3B)
2165    {
2166        opsel = (insnCode >> 11) & 15;
2167        // print OPSEL
2168        const bool opsel2Bit = (vop3Mode!=GCN_VOP3_VOP3P && vsrc1Used) ||
2169            (vop3Mode==GCN_VOP3_VOP3P && vsrc2Used);
2170        const bool opsel3Bit = (vsrc2Used && vop3Mode!=GCN_VOP3_VOP3P);
2171        if (vop3Mode!=GCN_VOP3_VOP3P)
2172        {
2173            opselMask |= (opsel2Bit?2:0) | (opsel3Bit?4:0) | 8;
2174            opselBaseMask = (15U<<11);
2175        }
2176        else // VOP3P
2177        {
2178            opselMask |= (opsel2Bit?6:2);
2179            opselBaseMask = (7U<<11);
2180        }
2181       
2182        if ((insnCode & (opselMask<<11)) != 0 &&
2183            ((insnCode & opselBaseMask) & ~(opselMask<<11)) == 0)
2184        {
2185            putChars(bufPtr, " op_sel:[", 9);
2186            *bufPtr++ = (insnCode&0x800) ? '1' : '0';
2187            *bufPtr++ = ',';
2188            if (vop3Mode==GCN_VOP3_VOP3P || vsrc1Used)
2189                *bufPtr++ = (insnCode&0x1000) ? '1' : '0';
2190            else
2191                // last bit 14-bit dest (for one operand instr)
2192                *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
2193            // print next opsel if next operand is present
2194            // for VOP3P: VSRC2, non VOP3P - VSRC1
2195            if (vop3Mode!=GCN_VOP3_VOP3P && vsrc1Used)
2196            {
2197                *bufPtr++ = ',';
2198                if (vsrc2Used)
2199                    *bufPtr++ = (insnCode&0x2000) ? '1' : '0';
2200                else
2201                    // last bit 14-bit dest (no third source operand)
2202                    *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
2203            }
2204            else if (vop3Mode==GCN_VOP3_VOP3P && vsrc2Used)
2205            {
2206                *bufPtr++ = ',';
2207                *bufPtr++ = (insnCode&0x2000) ? '1' : '0';
2208            }
2209            // only for VOP3P and VSRC2
2210            if (vsrc2Used && vop3Mode!=GCN_VOP3_VOP3P)
2211            {
2212                *bufPtr++ = ',';
2213                *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
2214            }
2215            *bufPtr++ = ']';
2216        }
2217    }
2218   
2219    // fi VOP3P encoding
2220    if (vop3Mode==GCN_VOP3_VOP3P)
2221    {
2222        // print OP_SEL_HI modifier
2223        cxuint opselHi = ((insnCode2 >> 27) & 3) | (vsrc2Used ? ((insnCode>>12)&4) : 0);
2224        if (opselHi != 3+(vsrc2Used?4:0))
2225        {
2226            putChars(bufPtr, " op_sel_hi:[", 12);
2227            *bufPtr++ = (insnCode2 & (1U<<27)) ? '1' : '0';
2228            *bufPtr++ = ',';
2229            *bufPtr++ = (insnCode2 & (1U<<28)) ? '1' : '0';
2230            if (vsrc2Used)
2231            {
2232                *bufPtr++ = ',';
2233                *bufPtr++ = (insnCode& 0x4000) ? '1' : '0';
2234            }
2235            *bufPtr++ = ']';
2236        }
2237        // print NEG_LO modifier
2238        if ((insnCode2&((3+(vsrc2Used?4:0))<<29)) != 0)
2239        {
2240            putChars(bufPtr, " neg_lo:[", 9);
2241            *bufPtr++ = (insnCode2 & (1U<<29)) ? '1' : '0';
2242            *bufPtr++ = ',';
2243            *bufPtr++ = (insnCode2 & (1U<<30)) ? '1' : '0';
2244            if (vsrc2Used)
2245            {
2246                *bufPtr++ = ',';
2247                *bufPtr++ = (insnCode2 & (1U<<31)) ? '1' : '0';
2248            }
2249            *bufPtr++ = ']';
2250        }
2251        // print NEG_HI modifier
2252        if ((insnCode & ((3+(vsrc2Used?4:0))<<8)) != 0)
2253        {
2254            putChars(bufPtr, " neg_hi:[", 9);
2255            *bufPtr++ = (insnCode & (1U<<8)) ? '1' : '0';
2256            *bufPtr++ = ',';
2257            *bufPtr++ = (insnCode & (1U<<9)) ? '1' : '0';
2258            if (vsrc2Used)
2259            {
2260                *bufPtr++ = ',';
2261                *bufPtr++ = (insnCode & (1U<<10)) ? '1' : '0';
2262            }
2263            *bufPtr++ = ']';
2264        }
2265    }
2266   
2267    const cxuint omod = (insnCode2>>27)&3;
2268    if (vop3Mode != GCN_VOP3_VOP3P && omod != 0)
2269    {
2270        const char* omodStr = (omod==3)?" div:2":(omod==2)?" mul:4":" mul:2";
2271        putChars(bufPtr, omodStr, 6);
2272    }
2273   
2274    const bool clamp = (!isGCN12 && gcnInsn.encoding == GCNENC_VOP3A &&
2275            (insnCode&0x800) != 0) || (isGCN12 && (insnCode&0x8000) != 0);
2276    if (clamp)
2277        putChars(bufPtr, " clamp", 6);
2278   
2279    /* print unused values of parts if not values are not default */
2280    if (!vdstUsed && vdst != 0)
2281    {
2282        putChars(bufPtr, " dst=", 5);
2283        bufPtr += itocstrCStyle(vdst, bufPtr, 6, 16);
2284    }
2285   
2286    if (!vsrc0Used)
2287    {
2288        if (vsrc0 != 0)
2289        {
2290            putChars(bufPtr, " src0=", 6);
2291            bufPtr += itocstrCStyle(vsrc0, bufPtr, 6, 16);
2292        }
2293        if (absFlags & 1)
2294            putChars(bufPtr, " abs0", 5);
2295        if ((insnCode2 & (1U<<29)) != 0)
2296            putChars(bufPtr, " neg0", 5);
2297    }
2298    if (!vsrc1Used)
2299    {
2300        if (vsrc1 != 0)
2301        {
2302            putChars(bufPtr, " vsrc1=", 7);
2303            bufPtr += itocstrCStyle(vsrc1, bufPtr, 6, 16);
2304        }
2305        if (absFlags & 2)
2306            putChars(bufPtr, " abs1", 5);
2307        if ((insnCode2 & (1U<<30)) != 0)
2308            putChars(bufPtr, " neg1", 5);
2309    }
2310    if (!vsrc2Used)
2311    {
2312        if (vsrc2 != 0)
2313        {
2314            putChars(bufPtr, " vsrc2=", 7);
2315            bufPtr += itocstrCStyle(vsrc2, bufPtr, 6, 16);
2316        }
2317        if (absFlags & 4)
2318            putChars(bufPtr, " abs2", 5);
2319        if ((insnCode2 & (1U<<31)) != 0)
2320            putChars(bufPtr, " neg2", 5);
2321    }
2322   
2323    // unused op_sel field
2324    if (isGCN14 && ((insnCode & opselBaseMask) & ~(opselMask<<11)) != 0 &&
2325        gcnInsn.encoding != GCNENC_VOP3B)
2326    {
2327        putChars(bufPtr, " op_sel=", 8);
2328        bufPtr += itocstrCStyle((insnCode>>11)&15, bufPtr, 6, 16);
2329    }
2330   
2331    const cxuint usedMask = 7 & ~(vsrc2CC?4:0);
2332    /* check whether instruction is this same like VOP2/VOP1/VOPC */
2333    bool isVOP1Word = false; // if can be write in single VOP dword
2334    if (vop3Mode == GCN_VOP3_VINTRP)
2335    {
2336        if (mode1 != GCN_NEW_OPCODE) /* check clamp and abs flags */
2337            isVOP1Word = !((insnCode&(7<<8)) != 0 || (insnCode2&(7<<29)) != 0 ||
2338                    clamp || omod!=0 || ((vsrc1 < 256 && mode1!=GCN_P0_P10_P20) ||
2339                    (mode1==GCN_P0_P10_P20 && vsrc1 >= 256)) ||
2340                    vsrc0 >= 256 || vsrc2 != 0);
2341    }
2342    else if (mode1 != GCN_ARG1_IMM && mode1 != GCN_ARG2_IMM)
2343    {
2344        const bool reqForVOP1Word = omod==0 && ((insnCode2&(usedMask<<29)) == 0);
2345        if (gcnInsn.encoding != GCNENC_VOP3B)
2346        {
2347            /* for VOPC */
2348            if (opcode < 256 && vdst == 106 /* vcc */ && vsrc1 >= 256 && vsrc2 == 0)
2349                isVOP1Word = true;
2350            /* for VOP1 */
2351            else if (vop3Mode == GCN_VOP3_VOP1 && vsrc1 == 0 && vsrc2 == 0)
2352                isVOP1Word = true;
2353            /* for VOP2 */
2354            else if (vop3Mode == GCN_VOP3_VOP2 && ((!vsrc1Used && vsrc1 == 0) || 
2355                /* distinguish for v_read/writelane and other vop2 encoded as vop3 */
2356                (((gcnInsn.mode&GCN_VOP3_SRC1_SGPR)==0) && vsrc1 >= 256) ||
2357                (((gcnInsn.mode&GCN_VOP3_SRC1_SGPR)!=0) && vsrc1 < 256)) &&
2358                ((mode1 != GCN_SRC2_VCC && vsrc2 == 0) ||
2359                (vsrc2 == 106 && mode1 == GCN_SRC2_VCC)))
2360                isVOP1Word = true;
2361            /* check clamp and abs and neg flags */
2362            if ((insnCode&(usedMask<<8)) != 0 || (insnCode2&(usedMask<<29)) != 0 || clamp)
2363                isVOP1Word = false;
2364        }
2365        /* for VOP2 encoded as VOP3b (v_addc....) */
2366        else if (gcnInsn.encoding == GCNENC_VOP3B && vop3Mode == GCN_VOP3_VOP2 &&
2367                vsrc1 >= 256 && sdst == 106 /* vcc */ &&
2368                ((vsrc2 == 106 && mode1 == GCN_DS2_VCC) || 
2369                    (vsrc2 == 0 && mode1 != GCN_DS2_VCC))) /* VOP3b */
2370            isVOP1Word = true;
2371       
2372        if (isVOP1Word && !reqForVOP1Word)
2373            isVOP1Word = false;
2374        if (opsel != 0)
2375            isVOP1Word = false;
2376    }
2377    else // force for v_madmk_f32 and v_madak_f32
2378        isVOP1Word = true;
2379   
2380    if (isVOP1Word) // add vop3 for distinguishing encoding
2381        putChars(bufPtr, " vop3", 5);
2382   
2383    output.forward(bufPtr-bufStart);
2384}
2385
2386void GCNDisasmUtils::decodeVINTRPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2387          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode)
2388{
2389    FastOutputBuffer& output = dasm.output;
2390    char* bufStart = output.reserve(90);
2391    char* bufPtr = bufStart;
2392    addSpaces(bufPtr, spacesToAdd);
2393    // print DST operand
2394    decodeGCNVRegOperand((insnCode>>18)&0xff, 1, bufPtr);
2395    *bufPtr++ = ',';
2396    *bufPtr++ = ' ';
2397    if ((gcnInsn.mode & GCN_MASK1) == GCN_P0_P10_P20)
2398        // print VINTRP param
2399        decodeVINTRPParam(insnCode&0xff, bufPtr);
2400    else
2401        // or VSRC0 operand
2402        decodeGCNVRegOperand(insnCode&0xff, 1, bufPtr);
2403    putChars(bufPtr, ", attr", 6);
2404    const cxuint attr = (insnCode>>10)&63;
2405    putByteToBuf(attr, bufPtr);
2406    *bufPtr++ = '.';
2407    *bufPtr++ = "xyzw"[((insnCode>>8)&3)]; // attrchannel
2408    output.forward(bufPtr-bufStart);
2409}
2410
2411void GCNDisasmUtils::decodeDSEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2412          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2413          uint32_t insnCode2)
2414{
2415    FastOutputBuffer& output = dasm.output;
2416    char* bufStart = output.reserve(105);
2417    char* bufPtr = bufStart;
2418    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
2419    addSpaces(bufPtr, spacesToAdd);
2420    bool vdstUsed = false;
2421    bool vaddrUsed = false;
2422    bool vdata0Used = false;
2423    bool vdata1Used = false;
2424    const cxuint vaddr = insnCode2&0xff;
2425    const cxuint vdata0 = (insnCode2>>8)&0xff;
2426    const cxuint vdata1 = (insnCode2>>16)&0xff;
2427    const cxuint vdst = insnCode2>>24;
2428   
2429    if (((gcnInsn.mode & GCN_ADDR_SRC) != 0 || (gcnInsn.mode & GCN_ONLYDST) != 0) &&
2430            (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2431    {
2432        /* vdst is dst */
2433        cxuint regsNum = (gcnInsn.mode&GCN_REG_DST_64)?2:1;
2434        if ((gcnInsn.mode&GCN_DS_96) != 0)
2435            regsNum = 3;
2436        if ((gcnInsn.mode&GCN_DS_128) != 0 || (gcnInsn.mode&GCN_DST128) != 0)
2437            regsNum = 4;
2438        // print VDST
2439        decodeGCNVRegOperand(vdst, regsNum, bufPtr);
2440        vdstUsed = true;
2441    }
2442    if ((gcnInsn.mode & GCN_ONLYDST) == 0 && (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2443    {
2444        /// print VADDR
2445        if (vdstUsed)
2446        {
2447            *bufPtr++ = ',';
2448            *bufPtr++ = ' ';
2449        }
2450        decodeGCNVRegOperand(vaddr, 1, bufPtr);
2451        vaddrUsed = true;
2452    }
2453   
2454    const uint16_t srcMode = (gcnInsn.mode & GCN_SRCS_MASK);
2455   
2456    if ((gcnInsn.mode & GCN_ONLYDST) == 0 &&
2457        (gcnInsn.mode & (GCN_ADDR_DST|GCN_ADDR_SRC)) != 0 && srcMode != GCN_NOSRC)
2458    {
2459        /* print two vdata */
2460        if (vaddrUsed || vdstUsed)
2461        {
2462            // comma after previous argument (VDST, VADDR)
2463            *bufPtr++ = ',';
2464            *bufPtr++ = ' ';
2465        }
2466        // determine number of register for VDATA0
2467        cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
2468        if ((gcnInsn.mode&GCN_DS_96) != 0)
2469            regsNum = 3;
2470        if ((gcnInsn.mode&GCN_DS_128) != 0)
2471            regsNum = 4;
2472        // print VDATA0
2473        decodeGCNVRegOperand(vdata0, regsNum, bufPtr);
2474        vdata0Used = true;
2475        if (srcMode == GCN_2SRCS)
2476        {
2477            *bufPtr++ = ',';
2478            *bufPtr++ = ' ';
2479            // print VDATA1
2480            decodeGCNVRegOperand(vdata1, (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr);
2481            vdata1Used = true;
2482        }
2483    }
2484   
2485    const cxuint offset = (insnCode&0xffff);
2486    // printing offsets (one 16-bit or two 8-bit)
2487    if (offset != 0)
2488    {
2489        if ((gcnInsn.mode & GCN_2OFFSETS) == 0) /* single offset */
2490        {
2491            putChars(bufPtr, " offset:", 8);
2492            bufPtr += itocstrCStyle(offset, bufPtr, 7, 10);
2493        }
2494        else
2495        {
2496            // if two 8-bit offsets (if supplied)
2497            if ((offset&0xff) != 0)
2498            {
2499                putChars(bufPtr, " offset0:", 9);
2500                putByteToBuf(offset&0xff, bufPtr);
2501            }
2502            if ((offset&0xff00) != 0)
2503            {
2504                putChars(bufPtr, " offset1:", 9);
2505                putByteToBuf((offset>>8)&0xff, bufPtr);
2506            }
2507        }
2508    }
2509   
2510    if ((!isGCN12 && (insnCode&0x20000)!=0) || (isGCN12 && (insnCode&0x10000)!=0))
2511        putChars(bufPtr, " gds", 4);
2512   
2513    // print value, if some are not used, but values is not default
2514    if (!vaddrUsed && vaddr != 0)
2515    {
2516        putChars(bufPtr, " vaddr=", 7);
2517        bufPtr += itocstrCStyle(vaddr, bufPtr, 6, 16);
2518    }
2519    if (!vdata0Used && vdata0 != 0)
2520    {
2521        putChars(bufPtr, " vdata0=", 8);
2522        bufPtr += itocstrCStyle(vdata0, bufPtr, 6, 16);
2523    }
2524    if (!vdata1Used && vdata1 != 0)
2525    {
2526        putChars(bufPtr, " vdata1=", 8);
2527        bufPtr += itocstrCStyle(vdata1, bufPtr, 6, 16);
2528    }
2529    if (!vdstUsed && vdst != 0)
2530    {
2531        putChars(bufPtr, " vdst=", 6);
2532        bufPtr += itocstrCStyle(vdst, bufPtr, 6, 16);
2533    }
2534    output.forward(bufPtr-bufStart);
2535}
2536
2537// print DATA FORMAT name table
2538static const char* mtbufDFMTTable[] =
2539{
2540    "invalid", "8", "16", "8_8", "32", "16_16", "10_11_11", "11_11_10",
2541    "10_10_10_2", "2_10_10_10", "8_8_8_8", "32_32", "16_16_16_16", "32_32_32",
2542    "32_32_32_32", "reserved"
2543};
2544
2545// print NUMBER FORMAT name table
2546static const char* mtbufNFMTTable[] =
2547{
2548    "unorm", "snorm", "uscaled", "sscaled",
2549    "uint", "sint", "snorm_ogl", "float"
2550};
2551
2552void GCNDisasmUtils::decodeMUBUFEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2553          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2554          uint32_t insnCode2)
2555{
2556    FastOutputBuffer& output = dasm.output;
2557    char* bufStart = output.reserve(170);
2558    char* bufPtr = bufStart;
2559    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
2560    const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
2561    const cxuint vaddr = insnCode2&0xff;
2562    const cxuint vdata = (insnCode2>>8)&0xff;
2563    const cxuint srsrc = (insnCode2>>16)&0x1f;
2564    const cxuint soffset = insnCode2>>24;
2565    const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
2566    if (mode1 != GCN_ARG_NONE)
2567    {
2568        addSpaces(bufPtr, spacesToAdd);
2569        if (mode1 != GCN_MUBUF_NOVAD)
2570        {
2571            // determine number of regs in VDATA
2572            cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
2573            if ((gcnInsn.mode & GCN_MUBUF_D16)!=0 && isGCN14)
2574                // 16-bit values packed into half of number of registers
2575                dregsNum = (dregsNum+1)>>1;
2576            if (insnCode2 & 0x800000U)
2577                dregsNum++; // tfe
2578            // print VDATA
2579            decodeGCNVRegOperand(vdata, dregsNum, bufPtr);
2580            *bufPtr++ = ',';
2581            *bufPtr++ = ' ';
2582            // determine number of vaddr registers
2583            /* for addr32 - idxen+offen or 1, for addr64 - 2 (idxen and offen is illegal) */
2584            const cxuint aregsNum = ((insnCode & 0x3000U)==0x3000U ||
2585                    /* addr64 only for older GCN than 1.2 */
2586                    (!isGCN12 && (insnCode & 0x8000U)))? 2 : 1;
2587            // print VADDR
2588            decodeGCNVRegOperand(vaddr, aregsNum, bufPtr);
2589            *bufPtr++ = ',';
2590            *bufPtr++ = ' ';
2591        }
2592        // print SRSRC
2593        decodeGCNOperandNoLit(dasm, srsrc<<2, 4, bufPtr, arch);
2594        *bufPtr++ = ',';
2595        *bufPtr++ = ' ';
2596        // print SOFFSET
2597        decodeGCNOperandNoLit(dasm, soffset, 1, bufPtr, arch);
2598    }
2599    else
2600        addSpaces(bufPtr, spacesToAdd-1);
2601   
2602    // print modifiers: (offen and idxen, glc)
2603    if (insnCode & 0x1000U)
2604        putChars(bufPtr, " offen", 6);
2605    if (insnCode & 0x2000U)
2606        putChars(bufPtr, " idxen", 6);
2607    const cxuint offset = insnCode&0xfff;
2608    if (offset != 0)
2609    {
2610        putChars(bufPtr, " offset:", 8);
2611        bufPtr += itocstrCStyle(offset, bufPtr, 7, 10);
2612    }
2613    if (insnCode & 0x4000U)
2614        putChars(bufPtr, " glc", 4);
2615   
2616    // print SLD if supplied
2617    if (((!isGCN12 || gcnInsn.encoding==GCNENC_MTBUF) && (insnCode2 & 0x400000U)!=0) ||
2618        ((isGCN12 && gcnInsn.encoding!=GCNENC_MTBUF) && (insnCode & 0x20000)!=0))
2619        putChars(bufPtr, " slc", 4);
2620   
2621    if (!isGCN12 && (insnCode & 0x8000U)!=0)
2622        putChars(bufPtr, " addr64", 7);
2623    if (gcnInsn.encoding!=GCNENC_MTBUF && (insnCode & 0x10000U) != 0)
2624        putChars(bufPtr, " lds", 4);
2625    if (insnCode2 & 0x800000U)
2626        putChars(bufPtr, " tfe", 4);
2627    // routine to decode MTBUF format (include default values)
2628    if (gcnInsn.encoding==GCNENC_MTBUF)
2629    {
2630        const cxuint dfmt = (insnCode>>19)&15;
2631        const cxuint nfmt = (insnCode>>23)&7;
2632        if (dfmt!=1 || nfmt!=0)
2633        {
2634            // in shortened form: format:[DFMT, NFMT]
2635            putChars(bufPtr, " format:[", 9);
2636            if (dfmt!=1)
2637            {
2638                // print DATA_FORMAT if not default
2639                const char* dfmtStr = mtbufDFMTTable[dfmt];
2640                putChars(bufPtr, dfmtStr, ::strlen(dfmtStr));
2641            }
2642            if (dfmt!=1 && nfmt!=0)
2643                *bufPtr++ = ',';
2644            if (nfmt!=0)
2645            {
2646                // print NUMBER_FORMAT if not default
2647                const char* nfmtStr = mtbufNFMTTable[nfmt];
2648                putChars(bufPtr, nfmtStr, ::strlen(nfmtStr));
2649            }
2650            *bufPtr++ = ']';
2651        }
2652    }
2653    // print value, if some are not used, but values is not default
2654    if (mode1 == GCN_ARG_NONE || mode1 == GCN_MUBUF_NOVAD)
2655    {
2656        if (vaddr != 0)
2657        {
2658            putChars(bufPtr, " vaddr=", 7);
2659            bufPtr += itocstrCStyle(vaddr, bufPtr, 6, 16);
2660        }
2661        if (vdata != 0)
2662        {
2663            putChars(bufPtr, " vdata=", 7);
2664            bufPtr += itocstrCStyle(vdata, bufPtr, 6, 16);
2665        }
2666    }
2667    // also SRSRC and SOFFSET if no argument in instruction
2668    if (mode1 == GCN_ARG_NONE)
2669    {
2670        if (srsrc != 0)
2671        {
2672            putChars(bufPtr, " srsrc=", 7);
2673            bufPtr += itocstrCStyle(srsrc, bufPtr, 6, 16);
2674        }
2675        if (soffset != 0)
2676        {
2677            putChars(bufPtr, " soffset=", 9);
2678            bufPtr += itocstrCStyle(soffset, bufPtr, 6, 16);
2679        }
2680    }
2681    output.forward(bufPtr-bufStart);
2682}
2683
2684void GCNDisasmUtils::decodeMIMGEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2685         uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2686         uint32_t insnCode2)
2687{
2688    const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
2689    FastOutputBuffer& output = dasm.output;
2690    char* bufStart = output.reserve(170);
2691    char* bufPtr = bufStart;
2692    addSpaces(bufPtr, spacesToAdd);
2693   
2694    const cxuint dmask = (insnCode>>8)&15;
2695    cxuint dregsNum = 4;
2696    // determine register number for VDATA
2697    if ((gcnInsn.mode & GCN_MIMG_VDATA4) == 0)
2698        dregsNum = ((dmask & 1)?1:0) + ((dmask & 2)?1:0) + ((dmask & 4)?1:0) +
2699                ((dmask & 8)?1:0);
2700   
2701    dregsNum = (dregsNum == 0) ? 1 : dregsNum;
2702    if (insnCode & 0x10000)
2703        dregsNum++; // tfe
2704   
2705    // print VDATA
2706    decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
2707    *bufPtr++ = ',';
2708    *bufPtr++ = ' ';
2709    // print VADDR
2710    decodeGCNVRegOperand(insnCode2&0xff,
2711                 std::max(4, (gcnInsn.mode&GCN_MIMG_VA_MASK)+1), bufPtr);
2712    *bufPtr++ = ',';
2713    *bufPtr++ = ' ';
2714    // print SRSRC
2715    decodeGCNOperandNoLit(dasm, ((insnCode2>>14)&0x7c),
2716                (((insnCode & 0x8000)!=0) && !isGCN14) ? 4: 8, bufPtr, arch);
2717   
2718    const cxuint ssamp = (insnCode2>>21)&0x1f;
2719    if ((gcnInsn.mode & GCN_MIMG_SAMPLE) != 0)
2720    {
2721        *bufPtr++ = ',';
2722        *bufPtr++ = ' ';
2723        // print SSAMP if supplied
2724        decodeGCNOperandNoLit(dasm, ssamp<<2, 4, bufPtr, arch);
2725    }
2726    if (dmask != 1)
2727    {
2728        putChars(bufPtr, " dmask:", 7);
2729        // print value dmask (0-15)
2730        if (dmask >= 10)
2731        {
2732            *bufPtr++ = '1';
2733            *bufPtr++ = '0' + dmask - 10;
2734        }
2735        else
2736            *bufPtr++ = '0' + dmask;
2737    }
2738   
2739    // print other modifiers (unorm, glc, slc, ...)
2740    if (insnCode & 0x1000)
2741        putChars(bufPtr, " unorm", 6);
2742    if (insnCode & 0x2000)
2743        putChars(bufPtr, " glc", 4);
2744    if (insnCode & 0x2000000)
2745        putChars(bufPtr, " slc", 4);
2746    if (insnCode & 0x8000)
2747    {
2748        if (!isGCN14)
2749            putChars(bufPtr, " r128", 5);
2750        else
2751            putChars(bufPtr, " a16", 4);
2752    }
2753    if (insnCode & 0x10000)
2754        putChars(bufPtr, " tfe", 4);
2755    if (insnCode & 0x20000)
2756        putChars(bufPtr, " lwe", 4);
2757    if (insnCode & 0x4000)
2758    {
2759        // DA modifier
2760        *bufPtr++ = ' ';
2761        *bufPtr++ = 'd';
2762        *bufPtr++ = 'a';
2763    }
2764    if ((arch & ARCH_GCN_1_2_4)!=0 && (insnCode2 & (1U<<31)) != 0)
2765        putChars(bufPtr, " d16", 4);
2766   
2767    // print value, if some are not used, but values is not default
2768    if ((gcnInsn.mode & GCN_MIMG_SAMPLE) == 0 && ssamp != 0)
2769    {
2770        putChars(bufPtr, " ssamp=", 7);
2771        bufPtr += itocstrCStyle(ssamp, bufPtr, 6, 16);
2772    }
2773    output.forward(bufPtr-bufStart);
2774}
2775
2776void GCNDisasmUtils::decodeEXPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2777            uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2778            uint32_t insnCode2)
2779{
2780    FastOutputBuffer& output = dasm.output;
2781    char* bufStart = output.reserve(100);
2782    char* bufPtr = bufStart;
2783    addSpaces(bufPtr, spacesToAdd);
2784    /* export target */
2785    const cxuint target = (insnCode>>4)&63;
2786    if (target >= 32)
2787    {
2788        // print paramXX
2789        putChars(bufPtr, "param", 5);
2790        const cxuint tpar = target-32;
2791        const cxuint digit2 = tpar/10;
2792        if (digit2 != 0)
2793            *bufPtr++ = '0' + digit2;
2794        *bufPtr++ = '0' + tpar - 10*digit2;
2795    }
2796    else if (target >= 12 && target <= 15)
2797    {
2798        // print posX
2799        putChars(bufPtr, "pos0", 4);
2800        bufPtr[-1] = '0' + target-12;
2801    }
2802    else if (target < 8)
2803    {
2804        // print mrtX
2805        putChars(bufPtr, "mrt0", 4);
2806        bufPtr[-1] = '0' + target;
2807    }
2808    else if (target == 8)
2809        putChars(bufPtr, "mrtz", 4);
2810    else if (target == 9)
2811        putChars(bufPtr, "null", 4);
2812    else
2813    {
2814        /* reserved */
2815        putChars(bufPtr, "ill_", 4);
2816        const cxuint digit2 = target/10U;
2817        *bufPtr++ = '0' + digit2;
2818        *bufPtr++ = '0' + target - 10U*digit2;
2819    }
2820   
2821    /* print vdata registers */
2822    cxuint vsrcsUsed = 0;
2823    for (cxuint i = 0; i < 4; i++)
2824    {
2825        *bufPtr++ = ',';
2826        *bufPtr++ = ' ';
2827        if (insnCode & (1U<<i))
2828        {
2829            if ((insnCode&0x400)==0)
2830            {
2831                decodeGCNVRegOperand((insnCode2>>(i<<3))&0xff, 1, bufPtr);
2832                vsrcsUsed |= 1<<i;
2833            }
2834            else
2835            {
2836                // if compr=1
2837                decodeGCNVRegOperand(((i>=2)?(insnCode2>>8):insnCode2)&0xff, 1, bufPtr);
2838                vsrcsUsed |= 1U<<(i>>1);
2839            }
2840        }
2841        else
2842            putChars(bufPtr, "off", 3);
2843    }
2844   
2845    // other modifiers
2846    if (insnCode&0x800)
2847        putChars(bufPtr, " done", 5);
2848    if (insnCode&0x400)
2849        putChars(bufPtr, " compr", 6);
2850    if (insnCode&0x1000)
2851    {
2852        // VM modifier
2853        *bufPtr++ = ' ';
2854        *bufPtr++ = 'v';
2855        *bufPtr++ = 'm';
2856    }
2857   
2858    // print value, if some are not used, but values is not default
2859    for (cxuint i = 0; i < 4; i++)
2860    {
2861        const cxuint val = (insnCode2>>(i<<3))&0xff;
2862        if ((vsrcsUsed&(1U<<i))==0 && val!=0)
2863        {
2864            putChars(bufPtr, " vsrc0=", 7);
2865            bufPtr[-2] += i; // number
2866            bufPtr += itocstrCStyle(val, bufPtr, 6, 16);
2867        }
2868    }
2869    output.forward(bufPtr-bufStart);
2870}
2871
2872// routine to print FLAT address including 'off' for GCN 1.4
2873void GCNDisasmUtils::printFLATAddr(cxuint flatMode, char*& bufPtr, uint32_t insnCode2)
2874{
2875    const cxuint vaddr = insnCode2&0xff;
2876    if (flatMode == 0)
2877        decodeGCNVRegOperand(vaddr, 2 , bufPtr); // addr
2878    else if (flatMode == GCN_FLAT_GLOBAL)
2879        decodeGCNVRegOperand(vaddr,
2880                // if off in SADDR, then single VGPR offset
2881                ((insnCode2>>16)&0x7f) == 0x7f ? 2 : 1, bufPtr); // addr
2882    else if (flatMode == GCN_FLAT_SCRATCH)
2883    {
2884        if (((insnCode2>>16)&0x7f) == 0x7f)
2885            decodeGCNVRegOperand(vaddr, 1, bufPtr); // addr
2886        else // no vaddr
2887            putChars(bufPtr, "off", 3);
2888    }
2889}
2890
2891void GCNDisasmUtils::decodeFLATEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2892            uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2893            uint32_t insnCode2)
2894{
2895    const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
2896    FastOutputBuffer& output = dasm.output;
2897    char* bufStart = output.reserve(150);
2898    char* bufPtr = bufStart;
2899    addSpaces(bufPtr, spacesToAdd);
2900    bool vdstUsed = false;
2901    bool vdataUsed = false;
2902    bool saddrUsed = false;
2903    const cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
2904    /// cmpswap store only to half of number of data registers
2905    cxuint dstRegsNum = ((gcnInsn.mode & GCN_CMPSWAP)!=0) ? (dregsNum>>1) :  dregsNum;
2906    const cxuint flatMode = gcnInsn.mode & GCN_FLAT_MODEMASK;
2907    // add tfe extra register if needed
2908    dstRegsNum = (!isGCN14 && (insnCode2 & 0x800000U)) ? dstRegsNum+1 : dstRegsNum;
2909   
2910    bool printAddr = false;
2911    if ((gcnInsn.mode & GCN_FLAT_ADST) == 0)
2912    {
2913        vdstUsed = true;
2914        // print VDST
2915        decodeGCNVRegOperand(insnCode2>>24, dstRegsNum, bufPtr);
2916        *bufPtr++ = ',';
2917        *bufPtr++ = ' ';
2918        printFLATAddr(flatMode, bufPtr, insnCode2);
2919        printAddr = true;
2920    }
2921    else
2922    {
2923        /* two vregs, because 64-bitness stored in PTR32 mode (at runtime) */
2924        printFLATAddr(flatMode, bufPtr, insnCode2);
2925        printAddr = true;
2926        if ((gcnInsn.mode & GCN_FLAT_NODST) == 0)
2927        {
2928            vdstUsed = true;
2929            *bufPtr++ = ',';
2930            *bufPtr++ = ' ';
2931            // print VDST
2932            decodeGCNVRegOperand(insnCode2>>24, dstRegsNum, bufPtr);
2933        }
2934    }
2935   
2936    if ((gcnInsn.mode & GCN_FLAT_NODATA) == 0) /* print data */
2937    {
2938        vdataUsed = true;
2939        *bufPtr++ = ',';
2940        *bufPtr++ = ' ';
2941        // print DATA field
2942        decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
2943    }
2944   
2945    if (flatMode != 0 && printAddr)
2946    {
2947        // if GLOBAL_ or SCRATCH_
2948        *bufPtr++ = ',';
2949        *bufPtr++ = ' ';
2950        cxuint saddr = (insnCode2>>16)&0x7f;
2951        if ((saddr&0x7f) != 0x7f)
2952            // print SADDR (GCN 1.4)
2953            decodeGCNOperandNoLit(dasm, saddr, flatMode == GCN_FLAT_SCRATCH ? 1 : 2,
2954                        bufPtr, arch, FLTLIT_NONE);
2955        else // off
2956            putChars(bufPtr, "off", 3);
2957        saddrUsed = true;
2958    }
2959   
2960    // get inst_offset, with sign if FLAT_SCRATCH, FLAT_GLOBAL
2961    const cxint instOffset = (flatMode != 0 && (insnCode&0x1000) != 0) ?
2962                -4096+(insnCode&0xfff) : insnCode&0xfff;
2963    if (isGCN14 && instOffset != 0)
2964    {
2965        putChars(bufPtr, " inst_offset:", 13);
2966        bufPtr += itocstrCStyle(instOffset, bufPtr, 7, 10);
2967    }
2968   
2969    // print other modifers
2970    if (isGCN14 && (insnCode & 0x2000U))
2971        putChars(bufPtr, " lds", 4);
2972    if (insnCode & 0x10000U)
2973        putChars(bufPtr, " glc", 4);
2974    if (insnCode & 0x20000U)
2975        putChars(bufPtr, " slc", 4);
2976    if (insnCode2 & 0x800000U)
2977    {
2978        if (!isGCN14)
2979            putChars(bufPtr, " tfe", 4);
2980        else
2981            // if GCN 1.4 this bit is NV
2982            putChars(bufPtr, " nv", 3);
2983    }
2984   
2985    // print value, if some are not used, but values is not default
2986    if (!vdataUsed && ((insnCode2>>8)&0xff) != 0)
2987    {
2988        putChars(bufPtr, " vdata=", 7);
2989        bufPtr += itocstrCStyle((insnCode2>>8)&0xff, bufPtr, 6, 16);
2990    }
2991    if (!vdstUsed && (insnCode2>>24) != 0)
2992    {
2993        putChars(bufPtr, " vdst=", 6);
2994        bufPtr += itocstrCStyle(insnCode2>>24, bufPtr, 6, 16);
2995    }
2996    if (flatMode != 0 && !saddrUsed && ((insnCode>>16)&0xff) != 0)
2997    {
2998        putChars(bufPtr, " saddr=", 7);
2999        bufPtr += itocstrCStyle((insnCode2>>16)&0xff, bufPtr, 6, 16);
3000    }
3001    output.forward(bufPtr-bufStart);
3002}
3003
3004/* main routine */
3005
3006void GCNDisassembler::disassemble()
3007{
3008    // select current label and reloc to first
3009    LabelIter curLabel = std::lower_bound(labels.begin(), labels.end(), labelStartOffset);
3010    RelocIter curReloc = std::lower_bound(relocations.begin(), relocations.end(),
3011        std::make_pair(startOffset, Relocation()),
3012          [](const std::pair<size_t,Relocation>& a, const std::pair<size_t, Relocation>& b)
3013          { return a.first < b.first; });
3014    NamedLabelIter curNamedLabel = std::lower_bound(namedLabels.begin(), namedLabels.end(),
3015        std::make_pair(labelStartOffset, CString()),
3016          [](const std::pair<size_t,CString>& a, const std::pair<size_t, CString>& b)
3017          { return a.first < b.first; });
3018   
3019    const uint32_t* codeWords = reinterpret_cast<const uint32_t*>(input);
3020
3021    const GPUArchitecture arch = getGPUArchitectureFromDeviceType(
3022                disassembler.getDeviceType());
3023    // set up GCN indicators
3024    const bool isGCN11 = (arch == GPUArchitecture::GCN1_1);
3025    const bool isGCN124 = (arch >= GPUArchitecture::GCN1_2);
3026    const bool isGCN14 = (arch >= GPUArchitecture::GCN1_4);
3027    const uint16_t curArchMask = 
3028            1U<<int(getGPUArchitectureFromDeviceType(disassembler.getDeviceType()));
3029    const size_t codeWordsNum = (inputSize>>2);
3030   
3031    if ((inputSize&3) != 0)
3032        output.write(64,
3033           "        /* WARNING: Code size is not aligned to 4-byte word! */\n");
3034    if (instrOutOfCode)
3035        output.write(54, "        /* WARNING: Unfinished instruction at end! */\n");
3036   
3037    bool prevIsTwoWord = false;
3038   
3039    size_t pos = 0;
3040    while (true)
3041    {
3042        writeLabelsToPosition(pos<<2, curLabel, curNamedLabel);
3043        if (pos >= codeWordsNum)
3044            break;
3045       
3046        const size_t oldPos = pos;
3047        cxbyte gcnEncoding = GCNENC_NONE;
3048        const uint32_t insnCode = ULEV(codeWords[pos++]);
3049        if (insnCode == 0)
3050        {
3051            /* fix for GalliumCOmpute disassemblying (assembler doesn't accep
3052             * with two scalar operands */
3053            size_t count;
3054            for (count = 1; pos < codeWordsNum && codeWords[pos]==0; count++, pos++);
3055            // put to output
3056            char* buf = output.reserve(40);
3057            size_t bufPos = 0;
3058            memcpy(buf+bufPos, ".fill ", 6);
3059            bufPos += 6;
3060            bufPos += itocstrCStyle(count, buf+bufPos, 20);
3061            memcpy(buf+bufPos, ", 4, 0\n", 7);
3062            bufPos += 7;
3063            output.forward(bufPos);
3064            continue;
3065        }
3066        uint32_t insnCode2 = 0;
3067       
3068       
3069        /* determine GCN encoding */
3070        if ((insnCode & 0x80000000U) != 0)
3071        {
3072            if ((insnCode & 0x40000000U) == 0)
3073            {
3074                // SOP???
3075                if  ((insnCode & 0x30000000U) == 0x30000000U)
3076                {
3077                    // SOP1/SOPK/SOPC/SOPP
3078                    const uint32_t encPart = (insnCode & 0x0f800000U);
3079                    if (encPart == 0x0e800000U)
3080                    {
3081                        // SOP1
3082                        if ((insnCode&0xff) == 0xff) // literal
3083                        {
3084                            if (pos < codeWordsNum)
3085                                insnCode2 = ULEV(codeWords[pos++]);
3086                        }
3087                        gcnEncoding = GCNENC_SOP1;
3088                    }
3089                    else if (encPart == 0x0f000000U)
3090                    {
3091                        // SOPC
3092                        if ((insnCode&0xff) == 0xff ||
3093                            (insnCode&0xff00) == 0xff00) // literal
3094                        {
3095                            if (pos < codeWordsNum)
3096                                insnCode2 = ULEV(codeWords[pos++]);
3097                        }
3098                        gcnEncoding = GCNENC_SOPC;
3099                    }
3100                    else if (encPart == 0x0f800000U) // SOPP
3101                        gcnEncoding = GCNENC_SOPP;
3102                    else // SOPK
3103                    {
3104                        gcnEncoding = GCNENC_SOPK;
3105                        const uint32_t opcode = ((insnCode>>23)&0x1f);
3106                        if ((!isGCN124 && opcode == 21) ||
3107                            (isGCN124 && opcode == 20))
3108                        {
3109                            if (pos < codeWordsNum)
3110                                insnCode2 = ULEV(codeWords[pos++]);
3111                        }
3112                    }
3113                }
3114                else
3115                {
3116                    // SOP2
3117                    if ((insnCode&0xff) == 0xff || (insnCode&0xff00) == 0xff00)
3118                    {
3119                        // literal
3120                        if (pos < codeWordsNum)
3121                            insnCode2 = ULEV(codeWords[pos++]);
3122                    }
3123                    gcnEncoding = GCNENC_SOP2;
3124                }
3125            }
3126            else
3127            {
3128                // SMRD and others
3129                const uint32_t encPart = (insnCode&0x3c000000U)>>26;
3130                if ((!isGCN124 && gcnSize11Table[encPart] && (encPart != 7 || isGCN11)) ||
3131                    (isGCN124 && gcnSize12Table[encPart]))
3132                {
3133                    if (pos < codeWordsNum)
3134                        insnCode2 = ULEV(codeWords[pos++]);
3135                }
3136                if (isGCN124)
3137                    gcnEncoding = gcnEncoding12Table[encPart];
3138                else
3139                    gcnEncoding = gcnEncoding11Table[encPart];
3140                if (gcnEncoding == GCNENC_FLAT && !isGCN11 && !isGCN124)
3141                    gcnEncoding = GCNENC_NONE; // illegal if not GCN1.1
3142            }
3143        }
3144        else
3145        {
3146            // some vector instructions
3147            if ((insnCode & 0x7e000000U) == 0x7c000000U)
3148            {
3149                // VOPC
3150                if ((insnCode&0x1ff) == 0xff || // literal
3151                    // SDWA, DDP
3152                    (isGCN124 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
3153                {
3154                    if (pos < codeWordsNum)
3155                        insnCode2 = ULEV(codeWords[pos++]);
3156                }
3157                gcnEncoding = GCNENC_VOPC;
3158            }
3159            else if ((insnCode & 0x7e000000U) == 0x7e000000U)
3160            {
3161                // VOP1
3162                if ((insnCode&0x1ff) == 0xff || // literal
3163                    // SDWA, DDP
3164                    (isGCN124 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
3165                {
3166                    if (pos < codeWordsNum)
3167                        insnCode2 = ULEV(codeWords[pos++]);
3168                }
3169                gcnEncoding = GCNENC_VOP1;
3170            }
3171            else
3172            {
3173                // VOP2
3174                const cxuint opcode = (insnCode >> 25)&0x3f;
3175                if ((!isGCN124 && (opcode == 32 || opcode == 33)) ||
3176                    (isGCN124 && (opcode == 23 || opcode == 24 ||
3177                    opcode == 36 || opcode == 37))) // V_MADMK and V_MADAK
3178                {
3179                    if (pos < codeWordsNum)
3180                        insnCode2 = ULEV(codeWords[pos++]);
3181                }
3182                else if ((insnCode&0x1ff) == 0xff || // literal
3183                    // SDWA, DDP
3184                    (isGCN124 && ((insnCode&0x1ff) == 0xf9 || (insnCode&0x1ff) == 0xfa)))
3185                {
3186                    if (pos < codeWordsNum)
3187                        insnCode2 = ULEV(codeWords[pos++]);
3188                }
3189                gcnEncoding = GCNENC_VOP2;
3190            }
3191        }
3192       
3193        prevIsTwoWord = (oldPos+2 == pos);
3194       
3195        if (disassembler.getFlags() & DISASM_HEXCODE)
3196        {
3197            char* buf = output.reserve(50);
3198            size_t bufPos = 0;
3199            buf[bufPos++] = '/';
3200            buf[bufPos++] = '*';
3201            if (disassembler.getFlags() & DISASM_CODEPOS)
3202            {
3203                // print code position
3204                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
3205                                buf+bufPos, 20, 16, 12, false);
3206                buf[bufPos++] = ':';
3207                buf[bufPos++] = ' ';
3208            }
3209            bufPos += itocstrCStyle(insnCode, buf+bufPos, 12, 16, 8, false);
3210            buf[bufPos++] = ' ';
3211            // if instruction is two word long
3212            if (prevIsTwoWord)
3213                bufPos += itocstrCStyle(insnCode2, buf+bufPos, 12, 16, 8, false);
3214            else
3215                bufPos += addSpacesOld(buf+bufPos, 8);
3216            buf[bufPos++] = '*';
3217            buf[bufPos++] = '/';
3218            buf[bufPos++] = ' ';
3219            output.forward(bufPos);
3220        }
3221        else // add spaces
3222        {
3223            if (disassembler.getFlags() & DISASM_CODEPOS)
3224            {
3225                // print only code position
3226                char* buf = output.reserve(30);
3227                size_t bufPos = 0;
3228                buf[bufPos++] = '/';
3229                buf[bufPos++] = '*';
3230                bufPos += itocstrCStyle(startOffset+(oldPos<<2),
3231                                buf+bufPos, 20, 16, 12, false);
3232                buf[bufPos++] = '*';
3233                buf[bufPos++] = '/';
3234                buf[bufPos++] = ' ';
3235                output.forward(bufPos);
3236            }
3237            else
3238            {
3239                // add spaces
3240                char* buf = output.reserve(8);
3241                output.forward(addSpacesOld(buf, 8));
3242            }
3243        }
3244       
3245        if (gcnEncoding == GCNENC_NONE)
3246        {
3247            // invalid encoding
3248            char* buf = output.reserve(24);
3249            size_t bufPos = 0;
3250            buf[bufPos++] = '.';
3251            buf[bufPos++] = 'i';
3252            buf[bufPos++] = 'n';
3253            buf[bufPos++] = 't';
3254            buf[bufPos++] = ' '; 
3255            bufPos += itocstrCStyle(insnCode, buf+bufPos, 11, 16);
3256            output.forward(bufPos);
3257        }
3258        else
3259        {
3260            const GCNEncodingOpcodeBits* encodingOpcodeTable = 
3261                    (isGCN124) ? gcnEncodingOpcode12Table : gcnEncodingOpcodeTable;
3262            const cxuint opcode =
3263                    (insnCode>>encodingOpcodeTable[gcnEncoding].bitPos) & 
3264                    ((1U<<encodingOpcodeTable[gcnEncoding].bits)-1U);
3265           
3266            /* decode instruction and put to output */
3267            const GCNEncodingSpace& encSpace = 
3268                (isGCN124) ? gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+3 + gcnEncoding] :
3269                  gcnInstrTableByCodeSpaces[gcnEncoding];
3270            const GCNInstruction* gcnInsn = gcnInstrTableByCode.get() +
3271                    encSpace.offset + opcode;
3272           
3273            const GCNInstruction defaultInsn = { nullptr, gcnInsn->encoding, GCN_STDMODE,
3274                        0, 0 };
3275            cxuint spacesToAdd = 16;
3276            bool isIllegal = false;
3277            if (!isGCN124 && gcnInsn->mnemonic != nullptr &&
3278                (curArchMask & gcnInsn->archMask) == 0 &&
3279                gcnEncoding == GCNENC_VOP3A)
3280            {    /* new overrides (VOP3A) */
3281                const GCNEncodingSpace& encSpace2 =
3282                        gcnInstrTableByCodeSpaces[GCNENC_MAXVAL+1];
3283                gcnInsn = gcnInstrTableByCode.get() + encSpace2.offset + opcode;
3284                if (gcnInsn->mnemonic == nullptr ||
3285                        (curArchMask & gcnInsn->archMask) == 0)
3286                    isIllegal = true; // illegal
3287            }
3288            else if (isGCN14 && gcnInsn->mnemonic != nullptr &&
3289                (curArchMask & gcnInsn->archMask) == 0 &&
3290                (gcnEncoding == GCNENC_VOP3A || gcnEncoding == GCNENC_VOP2 ||
3291                    gcnEncoding == GCNENC_VOP1))
3292            {
3293                /* new overrides (VOP1/VOP3A/VOP2 for GCN 1.4) */
3294                const GCNEncodingSpace& encSpace4 =
3295                        gcnInstrTableByCodeSpaces[2*GCNENC_MAXVAL+4 +
3296                                (gcnEncoding != GCNENC_VOP2) +
3297                                (gcnEncoding == GCNENC_VOP1)];
3298                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
3299                if (gcnInsn->mnemonic == nullptr ||
3300                        (curArchMask & gcnInsn->archMask) == 0)
3301                    isIllegal = true; // illegal
3302            }
3303            else if (isGCN14 && gcnEncoding == GCNENC_FLAT && ((insnCode>>14)&3)!=0)
3304            {
3305                // GLOBAL_/SCRATCH_* instructions
3306                const GCNEncodingSpace& encSpace4 =
3307                    gcnInstrTableByCodeSpaces[2*(GCNENC_MAXVAL+1)+2+3 +
3308                        ((insnCode>>14)&3)-1];
3309                gcnInsn = gcnInstrTableByCode.get() + encSpace4.offset + opcode;
3310                if (gcnInsn->mnemonic == nullptr ||
3311                        (curArchMask & gcnInsn->archMask) == 0)
3312                    isIllegal = true; // illegal
3313            }
3314            else if (gcnInsn->mnemonic == nullptr ||
3315                (curArchMask & gcnInsn->archMask) == 0)
3316                isIllegal = true;
3317           
3318            if (!isIllegal)
3319            {
3320                // put spaces between mnemonic and operands
3321                size_t k = ::strlen(gcnInsn->mnemonic);
3322                output.writeString(gcnInsn->mnemonic);
3323                spacesToAdd = spacesToAdd>=k+1?spacesToAdd-k:1;
3324            }
3325            else
3326            {
3327                // print illegal instruction mnemonic
3328                char* bufStart = output.reserve(40);
3329                char* bufPtr = bufStart;
3330                if (!isGCN124 || gcnEncoding != GCNENC_SMEM)
3331                    putChars(bufPtr, gcnEncodingNames[gcnEncoding],
3332                            ::strlen(gcnEncodingNames[gcnEncoding]));
3333                else /* SMEM encoding */
3334                    putChars(bufPtr, "SMEM", 4);
3335                putChars(bufPtr, "_ill_", 5);
3336                // opcode value
3337                bufPtr += itocstrCStyle(opcode, bufPtr , 6);
3338                const size_t linePos = bufPtr-bufStart;
3339                spacesToAdd = spacesToAdd >= (linePos+1)? spacesToAdd - linePos : 1;
3340                gcnInsn = &defaultInsn;
3341                output.forward(bufPtr-bufStart);
3342            }
3343           
3344            // determine float literal type to display
3345            const FloatLitType displayFloatLits = 
3346                    ((disassembler.getFlags()&DISASM_FLOATLITS) != 0) ?
3347                    (((gcnInsn->mode & GCN_MASK2) == GCN_FLOATLIT) ? FLTLIT_F32 : 
3348                    ((gcnInsn->mode & GCN_MASK2) == GCN_F16LIT) ? FLTLIT_F16 :
3349                     FLTLIT_NONE) : FLTLIT_NONE;
3350           
3351            // print instruction in correct encoding
3352            switch(gcnEncoding)
3353            {
3354                case GCNENC_SOPC:
3355                    GCNDisasmUtils::decodeSOPCEncoding(*this, pos, curReloc,
3356                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
3357                    break;
3358                case GCNENC_SOPP:
3359                    GCNDisasmUtils::decodeSOPPEncoding(*this, spacesToAdd, curArchMask, 
3360                                 *gcnInsn, insnCode, insnCode2, pos);
3361                    break;
3362                case GCNENC_SOP1:
3363                    GCNDisasmUtils::decodeSOP1Encoding(*this, pos, curReloc,
3364                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
3365                    break;
3366                case GCNENC_SOP2:
3367                    GCNDisasmUtils::decodeSOP2Encoding(*this, pos, curReloc,
3368                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
3369                    break;
3370                case GCNENC_SOPK:
3371                    GCNDisasmUtils::decodeSOPKEncoding(*this, pos, curReloc,
3372                               spacesToAdd, curArchMask, *gcnInsn, insnCode, insnCode2);
3373                    break;
3374                case GCNENC_SMRD:
3375                    if (isGCN124)
3376                        GCNDisasmUtils::decodeSMEMEncoding(*this, spacesToAdd, curArchMask,
3377                                  *gcnInsn, insnCode, insnCode2);
3378                    else
3379                        GCNDisasmUtils::decodeSMRDEncoding(*this, spacesToAdd, curArchMask,
3380                                  *gcnInsn, insnCode);
3381                    break;
3382                case GCNENC_VOPC:
3383                    GCNDisasmUtils::decodeVOPCEncoding(*this, pos, curReloc, spacesToAdd,
3384                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
3385                    break;
3386                case GCNENC_VOP1:
3387                    GCNDisasmUtils::decodeVOP1Encoding(*this, pos, curReloc, spacesToAdd,
3388                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
3389                    break;
3390                case GCNENC_VOP2:
3391                    GCNDisasmUtils::decodeVOP2Encoding(*this, pos, curReloc, spacesToAdd,
3392                           curArchMask, *gcnInsn, insnCode, insnCode2, displayFloatLits);
3393                    break;
3394                case GCNENC_VOP3A:
3395                    GCNDisasmUtils::decodeVOP3Encoding(*this, spacesToAdd, curArchMask,
3396                                 *gcnInsn, insnCode, insnCode2, displayFloatLits);
3397                    break;
3398                case GCNENC_VINTRP:
3399                    GCNDisasmUtils::decodeVINTRPEncoding(*this, spacesToAdd, curArchMask,
3400                                 *gcnInsn, insnCode);
3401                    break;
3402                case GCNENC_DS:
3403                    GCNDisasmUtils::decodeDSEncoding(*this, spacesToAdd, curArchMask,
3404                                 *gcnInsn, insnCode, insnCode2);
3405                    break;
3406                case GCNENC_MUBUF:
3407                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
3408                                 *gcnInsn, insnCode, insnCode2);
3409                    break;
3410                case GCNENC_MTBUF:
3411                    GCNDisasmUtils::decodeMUBUFEncoding(*this, spacesToAdd, curArchMask,
3412                                 *gcnInsn, insnCode, insnCode2);
3413                    break;
3414                case GCNENC_MIMG:
3415                    GCNDisasmUtils::decodeMIMGEncoding(*this, spacesToAdd, curArchMask,
3416                                 *gcnInsn, insnCode, insnCode2);
3417                    break;
3418                case GCNENC_EXP:
3419                    GCNDisasmUtils::decodeEXPEncoding(*this, spacesToAdd, curArchMask,
3420                                 *gcnInsn, insnCode, insnCode2);
3421                    break;
3422                case GCNENC_FLAT:
3423                    GCNDisasmUtils::decodeFLATEncoding(*this, spacesToAdd, curArchMask,
3424                                 *gcnInsn, insnCode, insnCode2);
3425                    break;
3426                default:
3427                    break;
3428            }
3429        }
3430        output.put('\n');
3431    }
3432    if (!dontPrintLabelsAfterCode)
3433        writeLabelsToEnd(codeWordsNum<<2, curLabel, curNamedLabel);
3434    output.flush();
3435    disassembler.getOutput().flush();
3436}
Note: See TracBrowser for help on using the repository browser.