source: CLRX/CLRadeonExtender/trunk/amdasm/GCNDisasmDecode.cpp @ 4849

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

CLRadeonExtender: GCNAsm: Some preparings in MUBUF encoding for GFX10. GCNDisasm: Fix SLC decoding in MUBUF/MTBUF for GFX10.

File size: 92.0 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <algorithm>
22#include <iostream>
23#include <cstring>
24#include <mutex>
25#include <memory>
26#include <CLRX/utils/Utilities.h>
27#include <CLRX/utils/GPUId.h>
28#include <CLRX/amdasm/Disassembler.h>
29#include <CLRX/utils/MemAccess.h>
30#include "GCNInternals.h"
31#include "GCNDisasmInternals.h"
32
33using namespace CLRX;
34
35// put chars to buffer (helper)
36static inline void putChars(char*& buf, const char* input, size_t size)
37{
38    ::memcpy(buf, input, size);
39    buf += size;
40}
41
42static inline void putCommaSpace(char*& bufPtr)
43{
44    *bufPtr++ = ',';
45    *bufPtr++ = ' ';
46}
47
48static const char* gcnOperandFloatTable[] =
49{
50    "0.5", "-0.5", "1.0", "-1.0", "2.0", "-2.0", "4.0", "-4.0"
51};
52
53union CLRX_INTERNAL FloatUnion
54{
55    float f;
56    uint32_t u;
57};
58
59// simple helpers for writing values: bytes, regranges
60
61static inline void putByteToBuf(cxuint op, char*& bufPtr)
62{
63    cxuint val = op;
64    if (val >= 100U)
65    {
66        cxuint digit2 = val/100U;
67        *bufPtr++ = digit2+'0';
68        val -= digit2*100U;
69    }
70    {
71        const cxuint digit1 = val/10U;
72        if (digit1 != 0 || op >= 100U)
73            *bufPtr++ = digit1 + '0';
74        *bufPtr++ = val-digit1*10U + '0';
75    }
76}
77
78static inline void putHexByteToBuf(cxuint op, char*& bufPtr)
79{
80    const cxuint digit0 = op&0xf;
81    const cxuint digit1 = (op&0xf0)>>4;
82    *bufPtr++ = '0';
83    *bufPtr++ = 'x';
84    if (digit1 != 0)
85        *bufPtr++ = (digit1<=9)?'0'+digit1:'a'+digit1-10;
86    *bufPtr++ = (digit0<=9)?'0'+digit0:'a'+digit0-10;
87}
88
89// print regranges
90static void regRanges(cxuint op, cxuint vregNum, char*& bufPtr)
91{
92    if (vregNum!=1)
93        *bufPtr++ = '[';
94    putByteToBuf(op, bufPtr);
95    if (vregNum!=1)
96    {
97        *bufPtr++ = ':';
98        op += vregNum-1;
99        if (op > 255)
100            op -= 256; // fix for VREGS
101        putByteToBuf(op, bufPtr);
102        *bufPtr++ = ']';
103    }
104}
105
106static void decodeGCNVRegOperand(cxuint op, cxuint vregNum, char*& bufPtr)
107{
108    *bufPtr++ = 'v';
109    return regRanges(op, vregNum, bufPtr);
110}
111
112/* parameters: dasm - disassembler, codePos - code position for relocation,
113 * relocIter, optional - if literal is optional (can be replaced by inline constant) */
114void GCNDisasmUtils::printLiteral(GCNDisassembler& dasm, size_t codePos,
115          RelocIter& relocIter, uint32_t literal, FloatLitType floatLit, bool optional)
116{
117    // if with relocation, just write
118    if (dasm.writeRelocation(dasm.startOffset + (codePos<<2)-4, relocIter))
119        return;
120    FastOutputBuffer& output = dasm.output;
121    char* bufStart = output.reserve(50);
122    char* bufPtr = bufStart;
123    if (optional && (int32_t(literal)<=64 && int32_t(literal)>=-16)) // use lit(...)
124    {
125        // use lit() to force correct encoding (avoid constants)
126        putChars(bufPtr, "lit(", 4);
127        bufPtr += itocstrCStyle<int32_t>(literal, bufPtr, 11, 10);
128        *bufPtr++ = ')';
129    }
130    else
131        bufPtr += itocstrCStyle(literal, bufPtr, 11, 16);
132    if (floatLit != FLTLIT_NONE)
133    {
134        // print float point (FP16 or FP32) literal in comment
135        FloatUnion fu;
136        fu.u = literal;
137        putChars(bufPtr, " /* ", 4);
138        if (floatLit == FLTLIT_F32)
139            bufPtr += ftocstrCStyle(fu.f, bufPtr, 20);
140        else
141            bufPtr += htocstrCStyle(fu.u, bufPtr, 20);
142        *bufPtr++ = (floatLit == FLTLIT_F32)?'f':'h';
143        putChars(bufPtr, " */", 3);
144    }
145    output.forward(bufPtr-bufStart);
146}
147
148void GCNDisasmUtils::decodeGCNOperandNoLit(GCNDisassembler& dasm, cxuint op,
149           cxuint regNum, char*& bufPtr, GPUArchMask arch, FloatLitType floatLit)
150{
151    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
152    const bool isGCN14 = ((arch&ARCH_GCN_1_4)!=0);
153    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
154    const cxuint maxSgprsNum = getGPUMaxAddrRegsNumByArchMask(arch, REGTYPE_SGPR);
155    if ((op < maxSgprsNum) || (op >= 256 && op < 512))
156    {
157        // vector
158        if (op >= 256)
159        {
160            *bufPtr++ = 'v';
161            op -= 256;
162        }
163        // scalar
164        else
165            *bufPtr++ = 's';
166        regRanges(op, regNum, bufPtr);
167        return;
168    }
169   
170    const cxuint op2 = op&~1U;
171    if (op2 == 106 || (!isGCN14 && !isGCN15 && (op2 == 108 || op2 == 110)) || op2 == 126 ||
172        (op2 == 104 && (arch&ARCH_RX2X0)!=0) ||
173        ((op2 == 102 || op2 == 104) && isGCN12))
174    {
175        // if not SGPR, but other scalar registers
176        switch(op2)
177        {
178            case 102:
179                putChars(bufPtr, "flat_scratch", 12);
180                break;
181            case 104:
182                if (isGCN12) // GCN1.2
183                    putChars(bufPtr, "xnack_mask", 10);
184                else // GCN1.1
185                    putChars(bufPtr, "flat_scratch", 12);
186                break;
187            case 106:
188                // vcc
189                putChars(bufPtr, "vcc", 3);
190                break;
191            case 108:
192                // tba
193                putChars(bufPtr, "tba", 3);
194                break;
195            case 110:
196                // tma
197                putChars(bufPtr, "tma", 3);
198                break;
199            case 126:
200                putChars(bufPtr, "exec", 4);
201                break;
202        }
203        // if full 64-bit register
204        if (regNum >= 2)
205        {
206            if (op&1) // unaligned!!
207                putChars(bufPtr, "_u!", 3);
208            if (regNum > 2)
209                putChars(bufPtr, "&ill!", 5);
210            return;
211        }
212        // suffix _lo or _hi (like vcc_lo or vcc_hi)
213        *bufPtr++ = '_';
214        if ((op&1) == 0)
215        { *bufPtr++ = 'l'; *bufPtr++ = 'o'; }
216        else
217        { *bufPtr++ = 'h'; *bufPtr++ = 'i'; }
218        return;
219    }
220   
221    if (op == 125 && isGCN15)
222    {
223        putChars(bufPtr, "null", 4);
224        return;
225    }
226   
227    if (op == 255) // if literal
228    {
229        putChars(bufPtr, "0x0", 3); // zero
230        return;
231    }
232   
233    cxuint ttmpStart = ((isGCN14 || isGCN15) ? 108 : 112);
234    if (op >= ttmpStart && op < 124)
235    {
236        // print ttmp register
237        putChars(bufPtr, "ttmp", 4);
238        regRanges(op-ttmpStart, regNum, bufPtr);
239        return;
240    }
241    if (op == 124)
242    {
243        // M0 register
244        *bufPtr++ = 'm';
245        *bufPtr++ = '0';
246        if (regNum > 1)
247            putChars(bufPtr, "&ill!", 5);
248        return;
249    }
250   
251    if (op >= 128 && op <= 192)
252    {
253        // nonnegative integer constant
254        op -= 128;
255        const cxuint digit1 = op/10U;
256        if (digit1 != 0)
257            *bufPtr++ = digit1 + '0';
258        *bufPtr++ = op-digit1*10U + '0';
259        return;
260    }
261    if (op > 192 && op <= 208)
262    {
263        // negative integer constant
264        *bufPtr++ = '-';
265        if (op >= 202)
266        {
267            *bufPtr++ = '1';
268            *bufPtr++ = op-202+'0';
269        }
270        else
271            *bufPtr++ = op-192+'0';
272        return;
273    }
274   
275    Flags disasmFlags = dasm.disassembler.getFlags();
276    if (op >= 240 && op < 248)
277    {
278        const char* inOp = gcnOperandFloatTable[op-240];
279        putChars(bufPtr, inOp, ::strlen(inOp));
280        if ((disasmFlags & DISASM_BUGGYFPLIT)!=0 && floatLit==FLTLIT_F16)
281            *bufPtr++ = 's';    /* old rules of assembler */
282        return;
283    }
284   
285    if (isGCN14)
286        // special registers in GCN1.4 (VEGA)
287        switch(op)
288        {
289            case 0xeb:
290                putChars(bufPtr, "shared_base", 11);
291                return;
292            case 0xec:
293                putChars(bufPtr, "shared_limit", 12);
294                return;
295            case 0xed:
296                putChars(bufPtr, "private_base", 12);
297                return;
298            case 0xee:
299                putChars(bufPtr, "private_limit", 13);
300                return;
301            case 0xef:
302                putChars(bufPtr, "pops_exiting_wave_id", 20);
303                return;
304        }
305   
306    switch(op)
307    {
308        case 248:
309            if (isGCN12 || isGCN15)
310            {
311                // 1/(2*PI)
312                putChars(bufPtr, "0.15915494", 10);
313                if ((disasmFlags & DISASM_BUGGYFPLIT)!=0 && floatLit==FLTLIT_F16)
314                    *bufPtr++ = 's';    /* old rules of assembler */
315                return;
316            }
317            break;
318        case 251:
319            putChars(bufPtr, "vccz", 4);
320            return;
321        case 252:
322            putChars(bufPtr, "execz", 5);
323            return;
324        case 253:
325            // scc
326            putChars(bufPtr, "scc", 3);
327            return;
328        case 254:
329            // lds
330            putChars(bufPtr, "lds", 3);
331            return;
332    }
333   
334    // reserved value (illegal)
335    putChars(bufPtr, "ill_", 4);
336    *bufPtr++ = '0'+op/100U;
337    *bufPtr++ = '0'+(op/10U)%10U;
338    *bufPtr++ = '0'+op%10U;
339}
340
341char* GCNDisasmUtils::decodeGCNOperand(GCNDisassembler& dasm, size_t codePos,
342              RelocIter& relocIter, cxuint op, cxuint regNum, GPUArchMask arch,
343              uint32_t literal, FloatLitType floatLit)
344{
345    FastOutputBuffer& output = dasm.output;
346    if (op == 255)
347    {
348        // if literal
349        printLiteral(dasm, codePos, relocIter, literal, floatLit, true);
350        return output.reserve(100);
351    }
352    char* bufStart = output.reserve(50);
353    char* bufPtr = bufStart;
354    decodeGCNOperandNoLit(dasm, op, regNum, bufPtr, arch, floatLit);
355    output.forward(bufPtr-bufStart);
356    return output.reserve(100);
357}
358
359// table of values sendmsg
360static const char* sendMsgCodeMessageTable[16] =
361{
362    "@0",
363    "interrupt",
364    "gs",
365    "gs_done",
366    "@4", "@5", "@6", "@7", "@8", "@9", "@10", "@11", "@12", "@13", "@14", "system"
367};
368
369// table of values sendmsg (GCN 1.4 VEGA)
370static const char* sendMsgCodeMessageTableVEGA[16] =
371{
372    "@0",
373    "interrupt",
374    "gs",
375    "gs_done",
376    "savewave",
377    "stall_wave_gen",
378    "halt_waves",
379    "ordered_ps_done",
380    "early_prim_dealloc",
381    "gs_alloc_req",
382    "get_doorbell",
383    "@11", "@12", "@13", "@14", "system"
384};
385
386
387static const char* sendGsOpMessageTable[4] =
388{ "nop", "cut", "emit", "emit-cut" };
389
390/* encoding routines */
391
392// add N spaces
393static void addSpaces(char*& bufPtr, cxuint spacesToAdd)
394{
395    for (cxuint k = spacesToAdd; k>0; k--)
396        *bufPtr++ = ' ';
397}
398
399void GCNDisasmUtils::decodeSOPCEncoding(GCNDisassembler& dasm, size_t codePos,
400         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
401         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
402{
403    FastOutputBuffer& output = dasm.output;
404    char* bufStart = output.reserve(90);
405    char* bufPtr = bufStart;
406    addSpaces(bufPtr, spacesToAdd);
407    output.forward(bufPtr-bufStart);
408   
409    // form: INSTR SRC0, SRC1
410    bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
411                     (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
412    putCommaSpace(bufPtr);
413    if ((gcnInsn.mode & GCN_SRC1_IMM) != 0)
414    {
415        // if immediate in SRC1
416        putHexByteToBuf((insnCode>>8)&0xff, bufPtr);
417        output.forward(bufPtr-bufStart);
418    }
419    else
420    {
421        output.forward(bufPtr-bufStart);
422        decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>8)&0xff,
423               (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal);
424    }
425}
426
427/// about label writer - label is workaround for class hermetization
428void GCNDisasmUtils::decodeSOPPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
429         GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
430         uint32_t literal, size_t pos)
431{
432    const bool isGCN14 = ((arch&ARCH_GCN_1_4)!=0);
433    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
434    FastOutputBuffer& output = dasm.output;
435    char* bufStart = output.reserve(70);
436    char* bufPtr = bufStart;
437    const cxuint imm16 = insnCode&0xffff;
438    switch(gcnInsn.mode&GCN_MASK1)
439    {
440        case GCN_IMM_REL:
441        {
442            // print relative address as label
443            const size_t branchPos = dasm.startOffset + ((pos + int16_t(imm16))<<2);
444            addSpaces(bufPtr, spacesToAdd);
445            output.forward(bufPtr-bufStart);
446            dasm.writeLocation(branchPos);
447            return;
448        }
449        case GCN_IMM_LOCKS:
450        {
451            bool prevLock = false;
452            addSpaces(bufPtr, spacesToAdd);
453            const bool isf7f = (isGCN15 && imm16 == 0xff7f) ||
454                    (!isGCN14 && !isGCN15 && imm16==0xf7f) ||
455                    (isGCN14 && imm16==0xcf7f) ;
456            // print vmcnt only if not highest value and if 0x[c]f7f value
457            if ((!isGCN14 && !isGCN15 && (imm16&15) != 15) ||
458                ((isGCN14 || isGCN15) && (imm16&0xc00f) != 0xc00f) || isf7f)
459            {
460                const cxuint lockCnt = (isGCN14 || isGCN15) ?
461                        ((imm16>>10)&0x30) + (imm16&15) : imm16&15;
462                putChars(bufPtr, "vmcnt(", 6);
463                // print value of lockCnt
464                const cxuint digit2 = lockCnt/10U;
465                if (lockCnt >= 10)
466                    *bufPtr++ = '0'+digit2;
467                *bufPtr++= '0' + lockCnt-digit2*10U;
468                *bufPtr++ = ')';
469                prevLock = true;
470            }
471            // print only if expcnt have not highest value (7)
472            if (((imm16>>4)&7) != 7 || isf7f)
473            {
474                if (prevLock)
475                    // print & before previous lock: vmcnt()
476                    putChars(bufPtr, " & ", 3);
477                putChars(bufPtr, "expcnt(", 7);
478                // print value
479                *bufPtr++ = '0' + ((imm16>>4)&7);
480                *bufPtr++ = ')';
481                prevLock = true;
482            }
483            // print only if lgkmcnt have not highest value (15)
484            if ((!isGCN15 && ((imm16>>8)&15) != 15) ||
485                (isGCN15 && ((imm16>>8)&63) != 63) || isf7f)
486            {
487                /* LGKMCNT bits is 4 (5????) */
488                const cxuint lockCnt = isGCN15 ? ((imm16>>8)&63) : ((imm16>>8)&15);
489                if (prevLock)
490                    // print & before previous lock: vmcnt()
491                    putChars(bufPtr, " & ", 3);
492                putChars(bufPtr, "lgkmcnt(", 8);
493                const cxuint digit2 = lockCnt/10U;
494                if (lockCnt >= 10)
495                    *bufPtr++ = '0'+digit2;
496                *bufPtr++= '0' + lockCnt-digit2*10U;
497                *bufPtr++ = ')';
498                prevLock = true;
499            }
500            if ((!isGCN14 && !isGCN15 && (imm16&0xf080) != 0) ||
501                (isGCN14 && (imm16&0x3080) != 0) || (isGCN15 && (imm16&0x0080) != 0))
502            {
503                /* additional info about imm16 */
504                if (prevLock)
505                    putChars(bufPtr, " :", 2);
506                bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
507            }
508            break;
509        }
510        case GCN_IMM_MSGS:
511        {
512            cxuint illMask = 0xfff0;
513            addSpaces(bufPtr, spacesToAdd);
514           
515            // print sendmsg
516            putChars(bufPtr, "sendmsg(", 8);
517            const cxuint msgType = imm16&15;
518            const char* msgName = ((isGCN14 || isGCN15) ?
519                    sendMsgCodeMessageTableVEGA[msgType] :
520                    sendMsgCodeMessageTable[msgType]);
521            cxuint minUnknownMsgType = (isGCN14 || isGCN15) ? 11 : 4;
522            if ((arch & ARCH_RX3X0) != 0 && msgType == 4)
523            {
524                msgName = "savewave"; // 4 - savewave
525                minUnknownMsgType = 5;
526            }
527            // put message name to buffer
528            while (*msgName != 0)
529                *bufPtr++ = *msgName++;
530           
531            // if also some arguments supplied (gsops)
532            if ((msgType&14) == 2 || (msgType >= minUnknownMsgType && msgType <= 14) ||
533                (imm16&0x3f0) != 0) // gs ops
534            {
535                putCommaSpace(bufPtr);
536                illMask = 0xfcc0; // set new illegal mask of bits
537                const cxuint gsopId = (imm16>>4)&3;
538                const char* gsopName = sendGsOpMessageTable[gsopId];
539                // put gsop name to buffer
540                while (*gsopName != 0)
541                    *bufPtr++ = *gsopName++;
542                if (gsopId!=0 || ((imm16>>8)&3)!=0)
543                {
544                    putCommaSpace(bufPtr);
545                    // print gsop value
546                    *bufPtr++ = '0' + ((imm16>>8)&3);
547                }
548            }
549            *bufPtr++ = ')';
550            // if some bits is not zero (illegal value)
551            if ((imm16&illMask) != 0)
552            {
553                *bufPtr++ = ' ';
554                *bufPtr++ = ':';
555                bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
556            }
557            break;
558        }
559        case GCN_IMM_NONE:
560            if (imm16 != 0)
561            {
562                addSpaces(bufPtr, spacesToAdd);
563                bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
564            }
565            break;
566        default:
567            addSpaces(bufPtr, spacesToAdd);
568            bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
569            break;
570    }
571    output.forward(bufPtr-bufStart);
572}
573
574void GCNDisasmUtils::decodeSOP1Encoding(GCNDisassembler& dasm, size_t codePos,
575         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
576         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
577{
578    FastOutputBuffer& output = dasm.output;
579    char* bufStart = output.reserve(80);
580    char* bufPtr = bufStart;
581    addSpaces(bufPtr, spacesToAdd);
582    bool isDst = (gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE;
583    // print destination if instruction have it
584    if (isDst)
585    {
586        output.forward(bufPtr-bufStart);
587        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
588                         (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
589    }
590   
591    if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
592    {
593        if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
594            // put ',' if destination and source
595            putCommaSpace(bufPtr);
596        // put SRC1
597        output.forward(bufPtr-bufStart);
598        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
599                         (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
600    }
601    else if ((insnCode&0xff) != 0)
602    {
603        // print value, if some are not used, but values is not default
604        putChars(bufPtr," ssrc=", 6);
605        bufPtr += itocstrCStyle((insnCode&0xff), bufPtr, 6, 16);
606    }
607    // print value, if some are not used, but values is not default
608    if (!isDst && ((insnCode>>16)&0x7f) != 0)
609    {
610        putChars(bufPtr, " sdst=", 6);
611        bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
612    }
613    output.forward(bufPtr-bufStart);
614}
615
616void GCNDisasmUtils::decodeSOP2Encoding(GCNDisassembler& dasm, size_t codePos,
617         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
618         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
619{
620    FastOutputBuffer& output = dasm.output;
621    char* bufStart = output.reserve(90);
622    char* bufPtr = bufStart;
623    addSpaces(bufPtr, spacesToAdd);
624    if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
625    {
626        // print destination
627        output.forward(bufPtr-bufStart);
628        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
629                         (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
630        putCommaSpace(bufPtr);
631    }
632    // print SRC0
633    output.forward(bufPtr-bufStart);
634    bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
635                     (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
636    putCommaSpace(bufPtr);
637    // print SRC1
638    output.forward(bufPtr-bufStart);
639    bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>8)&0xff,
640                 (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal);
641   
642    // print value, if some are not used, but values is not default
643    if ((gcnInsn.mode & GCN_MASK1) == GCN_DST_NONE && ((insnCode>>16)&0x7f) != 0)
644    {
645        putChars(bufPtr, " sdst=", 6);
646        bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
647    }
648    output.forward(bufPtr-bufStart);
649}
650
651// table hwreg names
652static const char* hwregNames[24] =
653{
654    "@0", "mode", "status", "trapsts",
655    "hw_id", "gpr_alloc", "lds_alloc", "ib_sts",
656    "pc_lo", "pc_hi", "inst_dw0", "inst_dw1",
657    "ib_dbg0", "ib_dbg1", "flush_ib", "sh_mem_bases",
658    "sq_shader_tba_lo", "sq_shader_tba_hi",
659    "sq_shader_tma_lo", "sq_shader_tma_hi",
660    "flat_scr_lo", "flat_scr_hi",
661    "xnack_mask", "pops_packer"
662};
663
664/// about label writer - label is workaround for class hermetization
665void GCNDisasmUtils::decodeSOPKEncoding(GCNDisassembler& dasm, size_t codePos,
666         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
667         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
668{
669    FastOutputBuffer& output = dasm.output;
670    char* bufStart = output.reserve(90);
671    char* bufPtr = bufStart;
672    addSpaces(bufPtr, spacesToAdd);
673    if ((gcnInsn.mode & GCN_IMM_DST) == 0 && (gcnInsn.mode&GCN_MASK1) != GCN_DST_NONE)
674    {
675        // if normal destination
676        output.forward(bufPtr-bufStart);
677        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
678                         (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
679        putCommaSpace(bufPtr);
680    }
681    const cxuint imm16 = insnCode&0xffff;
682    if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL)
683    {
684        // print relative address (as label)
685        const size_t branchPos = dasm.startOffset + ((codePos + int16_t(imm16))<<2);
686        output.forward(bufPtr-bufStart);
687        dasm.writeLocation(branchPos);
688        bufPtr = bufStart = output.reserve(60);
689    }
690    else if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_SREG)
691    {
692        // print hwreg()
693        putChars(bufPtr, "hwreg(", 6);
694        const cxuint hwregId = imm16&0x3f;
695        cxuint hwregNamesNum = 13 + ((arch&ARCH_GCN_1_2_4)!=0);
696        if ((arch&ARCH_GCN_1_4) != 0)
697            hwregNamesNum = 20;
698        if ((arch&ARCH_GCN_1_5) != 0)
699            hwregNamesNum = 24;
700        if (hwregId < hwregNamesNum)
701            putChars(bufPtr, hwregNames[hwregId], ::strlen(hwregNames[hwregId]));
702        else
703        {
704            // parametrized hwreg: hwreg(@0
705            const cxuint digit2 = hwregId/10U;
706            *bufPtr++ = '@';
707            *bufPtr++ = '0' + digit2;
708            *bufPtr++ = '0' + hwregId - digit2*10U;
709        }
710        putCommaSpace(bufPtr);
711        // start bit
712        putByteToBuf((imm16>>6)&31, bufPtr);
713        putCommaSpace(bufPtr);
714        // size in bits
715        putByteToBuf(((imm16>>11)&31)+1, bufPtr);
716        *bufPtr++ = ')';
717    }
718    else
719        bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
720   
721    if (gcnInsn.mode & GCN_IMM_DST)
722    {
723        putCommaSpace(bufPtr);
724        // print value, if some are not used, but values is not default
725        if (gcnInsn.mode & GCN_SOPK_CONST)
726        {
727            // for S_SETREG_IMM32_B32
728            bufPtr += itocstrCStyle(literal, bufPtr, 11, 16);
729            if (((insnCode>>16)&0x7f) != 0)
730            {
731                putChars(bufPtr, " sdst=", 6);
732                bufPtr += itocstrCStyle((insnCode>>16)&0x7f, bufPtr, 6, 16);
733            }
734        }
735        else if ((gcnInsn.mode&GCN_MASK1) != GCN_DST_NONE)
736        {
737            // for s_setreg_b32, print destination as source
738            output.forward(bufPtr-bufStart);
739            bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter,
740                     (insnCode>>16)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
741        }
742    }
743   
744    // print value, if some are not used, but values is not default
745    if ((gcnInsn.mode & GCN_MASK1) == GCN_DST_NONE && ((insnCode>>16)&0x7f) != 0)
746    {
747        putChars(bufPtr, " sdst=", 6);
748        bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
749    }
750    output.forward(bufPtr-bufStart);
751}
752
753void GCNDisasmUtils::decodeSMRDEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
754             GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode)
755{
756    FastOutputBuffer& output = dasm.output;
757    char* bufStart = output.reserve(100);
758    char* bufPtr = bufStart;
759    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
760    bool useDst = false;
761    bool useOthers = false;
762   
763    bool spacesAdded = false;
764    if (mode1 == GCN_SMRD_ONLYDST)
765    {
766        // print only destination
767        addSpaces(bufPtr, spacesToAdd);
768        decodeGCNOperandNoLit(dasm, (insnCode>>15)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
769                         bufPtr, arch);
770        useDst = true;
771        spacesAdded = true;
772    }
773    else if (mode1 != GCN_ARG_NONE)
774    {
775        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
776        addSpaces(bufPtr, spacesToAdd);
777        // print destination (1,2,4,8 or 16 registers)
778        decodeGCNOperandNoLit(dasm, (insnCode>>15)&0x7f, dregsNum, bufPtr, arch);
779        putCommaSpace(bufPtr);
780        // print SBASE (base address registers) (address or resource)
781        decodeGCNOperandNoLit(dasm, (insnCode>>8)&0x7e, (gcnInsn.mode&GCN_SBASE4)?4:2,
782                          bufPtr, arch);
783        putCommaSpace(bufPtr);
784        if (insnCode&0x100) // immediate value
785            bufPtr += itocstrCStyle(insnCode&0xff, bufPtr, 11, 16);
786        else // S register
787            decodeGCNOperandNoLit(dasm, insnCode&0xff, 1, bufPtr, arch);
788        // set what is printed
789        useDst = true;
790        useOthers = true;
791        spacesAdded = true;
792    }
793   
794    // print value, if some are not used, but values is not default
795    if (!useDst && (insnCode & 0x3f8000U) != 0)
796    {
797        addSpaces(bufPtr, spacesToAdd-1);
798        spacesAdded = true;
799        putChars(bufPtr, " sdst=", 6);
800        bufPtr += itocstrCStyle((insnCode>>15)&0x7f, bufPtr, 6, 16);
801    }
802    if (!useOthers && (insnCode & 0x7e00U)!=0)
803    {
804        if (!spacesAdded)
805            addSpaces(bufPtr, spacesToAdd-1);
806        spacesAdded = true;
807        putChars(bufPtr, " sbase=", 7);
808        bufPtr += itocstrCStyle((insnCode>>9)&0x3f, bufPtr, 6, 16);
809    }
810    if (!useOthers && (insnCode & 0xffU)!=0)
811    {
812        if (!spacesAdded)
813            addSpaces(bufPtr, spacesToAdd-1);
814        spacesAdded = true;
815        putChars(bufPtr, " offset=", 8);
816        bufPtr += itocstrCStyle(insnCode&0xff, bufPtr, 6, 16);
817    }
818    if (!useOthers && (insnCode & 0x100U)!=0)
819    {
820        if (!spacesAdded)
821            addSpaces(bufPtr, spacesToAdd-1);
822        spacesAdded = true;
823        putChars(bufPtr, " imm=1", 6);
824    }
825    output.forward(bufPtr-bufStart);
826}
827
828void GCNDisasmUtils::decodeSMEMEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
829         GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
830         uint32_t insnCode2)
831{
832    FastOutputBuffer& output = dasm.output;
833    char* bufStart = output.reserve(120);
834    char* bufPtr = bufStart;
835    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
836    bool useDst = false;
837    bool useOthers = false;
838    bool spacesAdded = false;
839    const bool isGCN14 = ((arch&ARCH_GCN_1_4) != 0);
840    const bool isGCN15 = ((arch&ARCH_GCN_1_5) != 0);
841    bool printOffset = false;
842   
843    if (mode1 == GCN_SMRD_ONLYDST)
844    {
845        // print only destination
846        addSpaces(bufPtr, spacesToAdd);
847        decodeGCNOperandNoLit(dasm, (insnCode>>6)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
848                         bufPtr, arch);
849        useDst = true;
850        spacesAdded = true;
851    }
852    else if (mode1 != GCN_ARG_NONE)
853    {
854        const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
855        addSpaces(bufPtr, spacesToAdd);
856        if ((mode1 & GCN_SMEM_NOSDATA) == 0)
857        {
858            if (mode1 & GCN_SMEM_SDATA_IMM)
859                // print immediate value
860                putHexByteToBuf((insnCode>>6)&0x7f, bufPtr);
861            else
862                // print destination (1,2,4,8 or 16 registers)
863                decodeGCNOperandNoLit(dasm, (insnCode>>6)&0x7f, dregsNum, bufPtr , arch);
864            putCommaSpace(bufPtr);
865            useDst = true;
866        }
867        // print SBASE (base address registers) (address or resource)
868        decodeGCNOperandNoLit(dasm, (insnCode<<1)&0x7e, (gcnInsn.mode&GCN_SBASE4)?4:2,
869                          bufPtr, arch);
870        putCommaSpace(bufPtr);
871        if ((!isGCN15 && (insnCode&0x20000)) ||
872            (isGCN15 && (insnCode2>>25)==0x7d)) // immediate value
873        {
874            if (!isGCN15 && isGCN14 && (insnCode & 0x4000) != 0)
875            {
876                // last 8-bit in second dword
877                decodeGCNOperandNoLit(dasm, (insnCode2>>25), 1, bufPtr , arch);
878                printOffset = true;
879            }
880            else
881            {
882                // print SOFFSET
883                uint32_t immMask =  isGCN14 ? 0x1fffff : 0xfffff;
884                bufPtr += itocstrCStyle(insnCode2 & immMask, bufPtr, 11, 16);
885            }
886        }
887        else // SOFFSET register
888        {
889            if (isGCN15 || (isGCN14 && (insnCode & 0x4000) != 0))
890                decodeGCNOperandNoLit(dasm, insnCode2>>25, 1, bufPtr, arch);
891            else
892                decodeGCNOperandNoLit(dasm, insnCode2&0xff, 1, bufPtr, arch);
893        }
894        useOthers = true;
895        spacesAdded = true;
896    }
897   
898    if ((insnCode & 0x10000) != 0)
899    {
900        if (!spacesAdded)
901            addSpaces(bufPtr, spacesToAdd-1);
902        spacesAdded = true;
903        // print GLC modifier
904        putChars(bufPtr, " glc", 4);
905    }
906   
907    if ((isGCN14 || isGCN15) && (insnCode & 0x8000) != 0)
908    {
909        if (!spacesAdded)
910            addSpaces(bufPtr, spacesToAdd-1);
911        spacesAdded = true;
912        // print NV modifier
913        putChars(bufPtr, " nv", 3);
914    }
915   
916    if (isGCN15 && (insnCode & 0x4000) != 0)
917    {
918        if (!spacesAdded)
919            addSpaces(bufPtr, spacesToAdd-1);
920        spacesAdded = true;
921        // print GLC modifier
922        putChars(bufPtr, " dlc", 4);
923    }
924   
925    if (printOffset)
926    {
927        // GCN 1.4 extra OFFSET
928        if (!spacesAdded)
929            addSpaces(bufPtr, spacesToAdd-1);
930        spacesAdded = true;
931        putChars(bufPtr, " offset:", 8);
932        bufPtr += itocstrCStyle(insnCode2 & 0x1fffff, bufPtr, 11, 16);
933    }
934   
935    // print value, if some are not used, but values is not default
936    if (!useDst && (insnCode & 0x1fc0U) != 0)
937    {
938        if (!spacesAdded)
939            addSpaces(bufPtr, spacesToAdd-1);
940        spacesAdded = true;
941        putChars(bufPtr, " sdata=", 7);
942        bufPtr += itocstrCStyle((insnCode>>6)&0x7f, bufPtr, 6, 16);
943    }
944    if (!useOthers && (insnCode & 0x3fU)!=0)
945    {
946        if (!spacesAdded)
947            addSpaces(bufPtr, spacesToAdd-1);
948        spacesAdded = true;
949        putChars(bufPtr, " sbase=", 7);
950        bufPtr += itocstrCStyle(insnCode&0x3f, bufPtr, 6, 16);
951    }
952    if (!useOthers && insnCode2!=0)
953    {
954        if (!spacesAdded)
955            addSpaces(bufPtr, spacesToAdd-1);
956        spacesAdded = true;
957        uint32_t immMask =  isGCN14 ? 0x1fffff : 0xfffff;
958        putChars(bufPtr, " offset=", 8);
959        bufPtr += itocstrCStyle(insnCode2&immMask, bufPtr, 12, 16);
960    }
961    if (!useOthers && !isGCN15 && (insnCode & 0x20000U)!=0)
962    {
963        if (!spacesAdded)
964            addSpaces(bufPtr, spacesToAdd-1);
965        spacesAdded = true;
966        putChars(bufPtr, " imm=1", 6);
967    }
968   
969    output.forward(bufPtr-bufStart);
970}
971
972// temporary structure to store operand modifiers and operand SRC0
973struct CLRX_INTERNAL VOPExtraWordOut
974{
975    uint16_t src0;
976    bool sextSrc0;
977    bool negSrc0;
978    bool absSrc0;
979    bool sextSrc1;
980    bool negSrc1;
981    bool absSrc1;
982    bool scalarSrc1;
983};
984
985// SDWA SEL field value names
986static const char* sdwaSelChoicesTbl[] =
987{
988    "byte0", "byte1", "byte2", "byte3", "word0", "word1", nullptr, "invalid"
989};
990
991// SDWA UNUSED field value names
992static const char* sdwaDstUnusedTbl[] =
993{
994    nullptr, "sext", "preserve", "invalid"
995};
996
997/* returns mask of abs,neg,sext for src0 and src1 argument and src0 register */
998static inline VOPExtraWordOut decodeVOPSDWAFlags(uint32_t insnCode2, GPUArchMask arch)
999{
1000    const bool isGCN14 = (arch & ARCH_GCN_1_4_5)!=0;
1001    return { uint16_t((insnCode2&0xff) +
1002        ((!isGCN14 || (insnCode2 & (1U<<23))==0) ? 256 : 0)),
1003        (insnCode2&(1U<<19))!=0, (insnCode2&(1U<<20))!=0, (insnCode2&(1U<<21))!=0,
1004        (insnCode2&(1U<<27))!=0, (insnCode2&(1U<<28))!=0, (insnCode2&(1U<<29))!=0,
1005        isGCN14 && ((insnCode2&(1U<<31))!=0) };
1006}
1007
1008// decode and print VOP SDWA encoding
1009static void decodeVOPSDWA(FastOutputBuffer& output, GPUArchMask arch, uint32_t insnCode2,
1010          bool src0Used, bool src1Used, bool vopc = false)
1011{
1012    char* bufStart = output.reserve(100);
1013    char* bufPtr = bufStart;
1014    const bool isGCN14 = ((arch&ARCH_GCN_1_4_5) != 0);
1015    cxuint dstSel = 6;
1016    cxuint dstUnused = 0;
1017    if (!isGCN14 || !vopc)
1018    {
1019        // not VEGA or not VOPC
1020        dstSel = (insnCode2>>8)&7;
1021        dstUnused = (insnCode2>>11)&3;
1022    }
1023    const cxuint src0Sel = (insnCode2>>16)&7;
1024    const cxuint src1Sel = (insnCode2>>24)&7;
1025   
1026    if (!isGCN14 || !vopc)
1027    {
1028        // not VEGA or not VOPC
1029        if (isGCN14 && (insnCode2 & 0xc000U) != 0)
1030        {
1031            cxuint omod = (insnCode2>>14)&3;
1032            const char* omodStr = (omod==3)?" div:2":(omod==2)?" mul:4":" mul:2";
1033            putChars(bufPtr, omodStr, 6);
1034        }
1035        if (insnCode2 & 0x2000)
1036            putChars(bufPtr, " clamp", 6);
1037       
1038        // print dst_sel:XXXX
1039        if (dstSel != 6)
1040        {
1041            putChars(bufPtr, " dst_sel:", 9);
1042            putChars(bufPtr, sdwaSelChoicesTbl[dstSel],
1043                    ::strlen(sdwaSelChoicesTbl[dstSel]));
1044        }
1045        // print dst_unused:XXX
1046        if (dstUnused!=0)
1047        {
1048            putChars(bufPtr, " dst_unused:", 12);
1049            putChars(bufPtr, sdwaDstUnusedTbl[dstUnused],
1050                    ::strlen(sdwaDstUnusedTbl[dstUnused]));
1051        }
1052    }
1053    // print src0_sel and src1_sel if used
1054    if (src0Sel!=6 && src0Used)
1055    {
1056        putChars(bufPtr, " src0_sel:", 10);
1057        putChars(bufPtr, sdwaSelChoicesTbl[src0Sel],
1058                 ::strlen(sdwaSelChoicesTbl[src0Sel]));
1059    }
1060    if (src1Sel!=6 && src1Used)
1061    {
1062        putChars(bufPtr, " src1_sel:", 10);
1063        putChars(bufPtr, sdwaSelChoicesTbl[src1Sel],
1064                 ::strlen(sdwaSelChoicesTbl[src1Sel]));
1065    }
1066    // unused but fields
1067    if (!src0Used)
1068    {
1069        if ((insnCode2&(1U<<19))!=0)
1070            putChars(bufPtr, " sext0", 6);
1071        if ((insnCode2&(1U<<20))!=0)
1072            putChars(bufPtr, " neg0", 5);
1073        if ((insnCode2&(1U<<21))!=0)
1074            putChars(bufPtr, " abs0", 5);
1075    }
1076    if (!src1Used)
1077    {
1078        if ((insnCode2&(1U<<27))!=0)
1079            putChars(bufPtr, " sext1", 6);
1080        if ((insnCode2&(1U<<28))!=0)
1081            putChars(bufPtr, " neg1", 5);
1082        if ((insnCode2&(1U<<29))!=0)
1083            putChars(bufPtr, " abs1", 5);
1084    }
1085   
1086    // add SDWA encoding specifier at end if needed (to avoid ambiguity)
1087    if (((isGCN14 && vopc) || (dstSel==6 && dstUnused==0)) &&
1088        src0Sel==6 && (insnCode2&(1U<<19))==0 && src1Sel==6 && (insnCode2&(1U<<27))==0)
1089        putChars(bufPtr, " sdwa", 5);
1090   
1091    output.forward(bufPtr-bufStart);
1092}
1093
1094/// DPP CTRL value table (only
1095static const char* dppCtrl130Tbl[] =
1096{
1097    " wave_shl", nullptr, nullptr, nullptr,
1098    " wave_rol", nullptr, nullptr, nullptr,
1099    " wave_shr", nullptr, nullptr, nullptr,
1100    " wave_ror", nullptr, nullptr, nullptr,
1101    " row_mirror", " row_half_mirror", " row_bcast15", " row_bcast31"
1102};
1103
1104static const char* dppCtrl130GFX10Tbl[] =
1105{
1106    nullptr, nullptr, nullptr, nullptr,
1107    nullptr, nullptr, nullptr, nullptr,
1108    nullptr, nullptr, nullptr, nullptr,
1109    nullptr, nullptr, nullptr, nullptr,
1110    " row_mirror", " row_half_mirror", nullptr, nullptr
1111};
1112
1113
1114/* returns mask of abs,neg,sext for src0 and src1 argument and src0 register */
1115static inline VOPExtraWordOut decodeVOPDPPFlags(uint32_t insnCode2)
1116{
1117    return { uint16_t((insnCode2&0xff)+256),
1118        false, (insnCode2&(1U<<20))!=0, (insnCode2&(1U<<21))!=0,
1119        false, (insnCode2&(1U<<22))!=0, (insnCode2&(1U<<23))!=0, false };
1120}
1121
1122static void decodeVOPDPP(FastOutputBuffer& output, GPUArchMask arch, uint32_t insnCode2,
1123        bool src0Used, bool src1Used)
1124{
1125    char* bufStart = output.reserve(110);
1126    char* bufPtr = bufStart;
1127    const cxuint dppCtrl = (insnCode2>>8)&0x1ff;
1128    const bool isGCN15 = (arch&ARCH_GCN_1_5)!=0;
1129   
1130    const char** dppCtrl130TblPtr = isGCN15 ? dppCtrl130GFX10Tbl : dppCtrl130Tbl;
1131   
1132    if (dppCtrl<256)
1133    {
1134        // print quadperm: quad_perm[A:B:C:D] A,B,C,D - 2-bit values
1135        putChars(bufPtr, " quad_perm:[", 12);
1136        *bufPtr++ = '0' + (dppCtrl&3);
1137        *bufPtr++ = ',';
1138        *bufPtr++ = '0' + ((dppCtrl>>2)&3);
1139        *bufPtr++ = ',';
1140        *bufPtr++ = '0' + ((dppCtrl>>4)&3);
1141        *bufPtr++ = ',';
1142        *bufPtr++ = '0' + ((dppCtrl>>6)&3);
1143        *bufPtr++ = ']';
1144    }
1145    else if ((dppCtrl >= 0x101 && dppCtrl <= 0x12f) && ((dppCtrl&0xf) != 0))
1146    {
1147        // row_shl, row_shr or row_ror
1148        if ((dppCtrl&0xf0) == 0)
1149            putChars(bufPtr, " row_shl:", 9);
1150        else if ((dppCtrl&0xf0) == 16)
1151            putChars(bufPtr, " row_shr:", 9);
1152        else
1153            putChars(bufPtr, " row_ror:", 9);
1154        // print shift
1155        putByteToBuf(dppCtrl&0xf, bufPtr);
1156    }
1157    else if (dppCtrl >= 0x130 && dppCtrl <= 0x143 && dppCtrl130TblPtr[dppCtrl-0x130]!=nullptr)
1158        // print other dpp modifier
1159        putChars(bufPtr, dppCtrl130TblPtr[dppCtrl-0x130],
1160                 ::strlen(dppCtrl130TblPtr[dppCtrl-0x130]));
1161    else if (isGCN15 && dppCtrl >= 0x150 && dppCtrl < 0x170)
1162    {
1163        putChars(bufPtr, dppCtrl<0x160 ? " row_share:": " row_xmask:", 11);
1164        putByteToBuf(dppCtrl&0xf, bufPtr);
1165    }
1166    // otherwise print value of dppctrl (illegal value)
1167    else if (dppCtrl != 0x100)
1168    {
1169        putChars(bufPtr, " dppctrl:", 9);
1170        bufPtr += itocstrCStyle(dppCtrl, bufPtr, 10, 16);
1171    }
1172   
1173    if (insnCode2 & (0x80000U)) // bound ctrl
1174        putChars(bufPtr, " bound_ctrl", 11);
1175   
1176    // print bank_mask and row_mask
1177    putChars(bufPtr, " bank_mask:", 11);
1178    putByteToBuf((insnCode2>>24)&0xf, bufPtr);
1179    putChars(bufPtr, " row_mask:", 10);
1180    putByteToBuf((insnCode2>>28)&0xf, bufPtr);
1181   
1182    if (isGCN15 && (insnCode2 & 0x40000)!=0)
1183        putChars(bufPtr, " fi", 3);
1184    // unused but fields
1185    if (!src0Used)
1186    {
1187        if ((insnCode2&(1U<<20))!=0)
1188            putChars(bufPtr, " neg0", 5);
1189        if ((insnCode2&(1U<<21))!=0)
1190            putChars(bufPtr, " abs0", 5);
1191    }
1192    if (!src1Used)
1193    {
1194        if ((insnCode2&(1U<<22))!=0)
1195            putChars(bufPtr, " neg1", 5);
1196        if ((insnCode2&(1U<<23))!=0)
1197            putChars(bufPtr, " abs1", 5);
1198    }
1199   
1200    output.forward(bufPtr-bufStart);
1201}
1202
1203static void decodeVOPDPP8(FastOutputBuffer& output, uint32_t insnCode2, bool fiFlag)
1204{
1205    char* bufStart = output.reserve(50);
1206    char* bufPtr = bufStart;
1207   
1208    putChars(bufPtr, " dpp8:[", 7);
1209    for (cxuint i=0; i < 8; i++)
1210    {
1211        *bufPtr++ = '0' + ((insnCode2>>(8 + 3*i))&7);
1212        *bufPtr++ = (i!=7) ? ',' : ']';
1213    }
1214   
1215    if (fiFlag)
1216        putChars(bufPtr, " fi", 3);
1217   
1218    output.forward(bufPtr-bufStart);
1219}
1220
1221void GCNDisasmUtils::decodeVOPCEncoding(GCNDisassembler& dasm, size_t codePos,
1222         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
1223         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
1224         FloatLitType displayFloatLits, Flags flags)
1225{
1226    FastOutputBuffer& output = dasm.output;
1227    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4_5)!=0);
1228    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
1229    char* bufStart = output.reserve(120);
1230    char* bufPtr = bufStart;
1231    addSpaces(bufPtr, spacesToAdd);
1232   
1233    const cxuint src0Field = (insnCode&0x1ff);
1234    // extra flags are zeroed by default
1235    VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
1236    if ((arch & ARCH_GCN_1_4_5) != 0 && src0Field==0xf9 && (literal & 0x8000) != 0)
1237    {
1238        // SDWAB replacement of SDST
1239        output.forward(bufPtr-bufStart);
1240        bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter,
1241                            (literal>>8)&0x7f, 2, arch);
1242        putCommaSpace(bufPtr);
1243    }
1244    else if ((gcnInsn.mode & GCN_VOPC_NOVCC) == 0) // just vcc
1245    {
1246        if (!isGCN15 || (flags&DISASM_WAVE32)==0 || (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0)
1247            putChars(bufPtr, "vcc, ", 5);
1248        else
1249            putChars(bufPtr, "vcc_lo, ", 8);
1250    }
1251   
1252    if (isGCN12)
1253    {
1254        // return VOP SDWA/DPP flags for operands
1255        if (src0Field == 0xf9)
1256            extraFlags = decodeVOPSDWAFlags(literal, arch);
1257        else if (src0Field == 0xfa)
1258            extraFlags = decodeVOPDPPFlags(literal);
1259        else if (isGCN15 && (src0Field == 0xe9 || src0Field == 0xea))
1260            extraFlags.src0 = uint16_t((literal&0xff)+256);
1261        else
1262            extraFlags.src0 = src0Field;
1263    }
1264    else
1265        extraFlags.src0 = src0Field;
1266   
1267    // apply sext(), negation and abs() if applied
1268    if (extraFlags.sextSrc0)
1269        putChars(bufPtr, "sext(", 5);
1270    if (extraFlags.negSrc0)
1271        *bufPtr++ = '-';
1272    if (extraFlags.absSrc0)
1273        putChars(bufPtr, "abs(", 4);
1274   
1275    output.forward(bufPtr-bufStart);
1276    // print SRC0
1277    bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
1278                 (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1279    // closing for abs and sext
1280    if (extraFlags.absSrc0)
1281        *bufPtr++ = ')';
1282    if (extraFlags.sextSrc0)
1283        *bufPtr++ = ')';
1284    putCommaSpace(bufPtr);
1285   
1286    // apply sext(), negation and abs() if applied
1287    if (extraFlags.sextSrc1)
1288        putChars(bufPtr, "sext(", 5);
1289   
1290    if (extraFlags.negSrc1)
1291        *bufPtr++ = '-';
1292    if (extraFlags.absSrc1)
1293        putChars(bufPtr, "abs(", 4);
1294   
1295    // print SRC1
1296    decodeGCNOperandNoLit(dasm, ((insnCode>>9)&0xff) + (extraFlags.scalarSrc1 ? 0 : 256),
1297                (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr, arch);
1298    // closing for abs and sext
1299    if (extraFlags.absSrc1)
1300        *bufPtr++ = ')';
1301    if (extraFlags.sextSrc1)
1302        *bufPtr++ = ')';
1303   
1304    output.forward(bufPtr-bufStart);
1305    if (isGCN12)
1306    {
1307        // print extra SDWA/DPP modifiers
1308        if (src0Field == 0xf9)
1309            decodeVOPSDWA(output, arch, literal, true, true, true);
1310        else if (src0Field == 0xfa)
1311            decodeVOPDPP(output, arch, literal, true, true);
1312        else if (isGCN15)
1313        {
1314            if (src0Field == 0xe9)
1315                decodeVOPDPP8(output, literal, false);
1316            else if (src0Field == 0xea)
1317                decodeVOPDPP8(output, literal, true);
1318        }
1319    }
1320}
1321
1322void GCNDisasmUtils::decodeVOP1Encoding(GCNDisassembler& dasm, size_t codePos,
1323         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
1324         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
1325         FloatLitType displayFloatLits)
1326{
1327    FastOutputBuffer& output = dasm.output;
1328    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4_5)!=0);
1329    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
1330    char* bufStart = output.reserve(130);
1331    char* bufPtr = bufStart;
1332   
1333    const cxuint src0Field = (insnCode&0x1ff);
1334    // extra flags are zeroed by default
1335    VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
1336   
1337    if (isGCN12)
1338    {
1339        // return extra flags from SDWA/DPP encoding
1340        if (src0Field == 0xf9)
1341            extraFlags = decodeVOPSDWAFlags(literal, arch);
1342        else if (src0Field == 0xfa)
1343            extraFlags = decodeVOPDPPFlags(literal);
1344        else if (isGCN15 && (src0Field == 0xe9 || src0Field == 0xea))
1345            extraFlags.src0 = uint16_t((literal&0xff)+256);
1346        else
1347            extraFlags.src0 = src0Field;
1348    }
1349    else
1350        extraFlags.src0 = src0Field;
1351   
1352    bool argsUsed = true;
1353    if ((gcnInsn.mode & GCN_MASK1) != GCN_VOP_ARG_NONE)
1354    {
1355        addSpaces(bufPtr, spacesToAdd);
1356        if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_SGPR)
1357            // print DST as SGPR
1358            decodeGCNVRegOperand(((insnCode>>17)&0xff),
1359                     (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr);
1360        else
1361            // print DST as normal VGPR
1362            decodeGCNOperandNoLit(dasm, ((insnCode>>17)&0xff),
1363                          (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr, arch);
1364        putCommaSpace(bufPtr);
1365        // apply sext, negation and abs if supplied
1366        if (extraFlags.sextSrc0)
1367            putChars(bufPtr, "sext(", 5);
1368       
1369        if (extraFlags.negSrc0)
1370            *bufPtr++ = '-';
1371        if (extraFlags.absSrc0)
1372            putChars(bufPtr, "abs(", 4);
1373        output.forward(bufPtr-bufStart);
1374        // print SRC0
1375        bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
1376                     (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1377        // closing sext and abs
1378        if (extraFlags.absSrc0)
1379            *bufPtr++ = ')';
1380        if (extraFlags.sextSrc0)
1381            *bufPtr++ = ')';
1382    }
1383    else if ((insnCode & 0x1fe01ffU) != 0)
1384    {
1385        // unused, but set fields
1386        addSpaces(bufPtr, spacesToAdd);
1387        if ((insnCode & 0x1fe0000U) != 0)
1388        {
1389            putChars(bufPtr, "vdst=", 5);
1390            bufPtr += itocstrCStyle((insnCode>>17)&0xff, bufPtr, 6, 16);
1391            if ((insnCode & 0x1ff) != 0)
1392                *bufPtr++ = ' ';
1393        }
1394        if ((insnCode & 0x1ff) != 0)
1395        {
1396            putChars(bufPtr, "src0=", 5);
1397            bufPtr += itocstrCStyle(insnCode&0x1ff, bufPtr, 6, 16);
1398        }
1399        argsUsed = false;
1400    }
1401    output.forward(bufPtr-bufStart);
1402    if (isGCN12)
1403    {
1404        // print extra SDWA/DPP modifiers
1405        if (src0Field == 0xf9)
1406            decodeVOPSDWA(output, arch, literal, argsUsed, false);
1407        else if (src0Field == 0xfa)
1408            decodeVOPDPP(output, arch, literal, argsUsed, false);
1409        else if (isGCN15)
1410        {
1411            if (src0Field == 0xe9)
1412                decodeVOPDPP8(output, literal, false);
1413            else if (src0Field == 0xea)
1414                decodeVOPDPP8(output, literal, true);
1415        }
1416    }
1417}
1418
1419void GCNDisasmUtils::decodeVOP2Encoding(GCNDisassembler& dasm, size_t codePos,
1420         RelocIter& relocIter, cxuint spacesToAdd, GPUArchMask arch,
1421         const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
1422         FloatLitType displayFloatLits, Flags flags)
1423{
1424    FastOutputBuffer& output = dasm.output;
1425    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4_5)!=0);
1426    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
1427    char* bufStart = output.reserve(150);
1428    char* bufPtr = bufStart;
1429   
1430    addSpaces(bufPtr, spacesToAdd);
1431    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1432   
1433    const cxuint src0Field = (insnCode&0x1ff);
1434    // extra flags are zeroed by default
1435    VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
1436   
1437    if (isGCN12)
1438    {
1439        // return extra flags from SDWA/DPP encoding
1440        if (src0Field == 0xf9)
1441            extraFlags = decodeVOPSDWAFlags(literal, arch);
1442        else if (src0Field == 0xfa)
1443            extraFlags = decodeVOPDPPFlags(literal);
1444        else if (isGCN15 && (src0Field == 0xe9 || src0Field == 0xea))
1445            extraFlags.src0 = uint16_t((literal&0xff)+256);
1446        else
1447            extraFlags.src0 = src0Field;
1448    }
1449    else
1450        extraFlags.src0 = src0Field;
1451   
1452    if (mode1 != GCN_DS1_SGPR)
1453        // print DST as SGPR
1454        decodeGCNVRegOperand(((insnCode>>17)&0xff),
1455                     (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr);
1456    else
1457        decodeGCNOperandNoLit(dasm, ((insnCode>>17)&0xff),
1458                 (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr, arch);
1459   
1460    // add VCC if V_ADD_XXX or other instruction VCC as DST
1461    if (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC)
1462    {
1463        if (!isGCN15 || (flags&DISASM_WAVE32)==0 || (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0)
1464            putChars(bufPtr, ", vcc", 5);
1465        else
1466            putChars(bufPtr, ", vcc_lo", 8);
1467    }
1468    putCommaSpace(bufPtr);
1469    // apply sext, negation and abs if supplied
1470    if (extraFlags.sextSrc0)
1471        putChars(bufPtr, "sext(", 5);
1472    if (extraFlags.negSrc0)
1473        *bufPtr++ = '-';
1474    if (extraFlags.absSrc0)
1475        putChars(bufPtr, "abs(", 4);
1476    output.forward(bufPtr-bufStart);
1477    // print SRC0
1478    bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
1479                 (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1480    // closing sext and abs
1481    if (extraFlags.absSrc0)
1482        *bufPtr++ = ')';
1483    if (extraFlags.sextSrc0)
1484        *bufPtr++ = ')';
1485    if (mode1 == GCN_ARG1_IMM)
1486    {
1487        // extra immediate (like V_MADMK_F32)
1488        putCommaSpace(bufPtr);
1489        output.forward(bufPtr-bufStart);
1490        printLiteral(dasm, codePos, relocIter, literal, displayFloatLits, false);
1491        bufStart = bufPtr = output.reserve(100);
1492    }
1493    putCommaSpace(bufPtr);
1494    // apply sext, negation and abs if supplied
1495    if (extraFlags.sextSrc1)
1496        putChars(bufPtr, "sext(", 5);
1497   
1498    if (extraFlags.negSrc1)
1499        *bufPtr++ = '-';
1500    if (extraFlags.absSrc1)
1501        putChars(bufPtr, "abs(", 4);
1502    // print SRC0
1503    if (mode1 == GCN_DS1_SGPR || mode1 == GCN_SRC1_SGPR)
1504    {
1505        output.forward(bufPtr-bufStart);
1506        bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter,
1507                 ((insnCode>>9)&0xff), (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch);
1508    }
1509    else
1510        decodeGCNOperandNoLit(dasm, ((insnCode>>9)&0xff) +
1511                (extraFlags.scalarSrc1 ? 0 : 256),
1512                (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr, arch);
1513    // closing sext and abs
1514    if (extraFlags.absSrc1)
1515        *bufPtr++ = ')';
1516    if (extraFlags.sextSrc1)
1517        *bufPtr++ = ')';
1518    if (mode1 == GCN_ARG2_IMM)
1519    {
1520        // extra immediate (like V_MADAK_F32)
1521        putCommaSpace(bufPtr);
1522        output.forward(bufPtr-bufStart);
1523        printLiteral(dasm, codePos, relocIter, literal, displayFloatLits, false);
1524    }
1525    else if (mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC)
1526    {
1527        // VCC like in V_CNDMASK_B32 or V_SUBB_B32
1528        if (!isGCN15 || (flags&DISASM_WAVE32)==0 || (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0)
1529            putChars(bufPtr, ", vcc", 5);
1530        else
1531            putChars(bufPtr, ", vcc_lo", 8);
1532        output.forward(bufPtr-bufStart);
1533    }
1534    else
1535        output.forward(bufPtr-bufStart);
1536    if (isGCN12)
1537    {
1538        // print extra SDWA/DPP modifiers
1539        if (src0Field == 0xf9)
1540            decodeVOPSDWA(output, arch, literal, true, true);
1541        else if (src0Field == 0xfa)
1542            decodeVOPDPP(output, arch, literal, true, true);
1543        else if (isGCN15)
1544        {
1545            if (src0Field == 0xe9)
1546                decodeVOPDPP8(output, literal, false);
1547            else if (src0Field == 0xea)
1548                decodeVOPDPP8(output, literal, true);
1549        }
1550    }
1551}
1552
1553// VINTRP param names
1554static const char* vintrpParamsTbl[] =
1555{ "p10", "p20", "p0" };
1556
1557static void decodeVINTRPParam(uint16_t p, char*& bufPtr)
1558{
1559    if (p >= 3)
1560    {
1561        putChars(bufPtr, "invalid_", 8);
1562        bufPtr += itocstrCStyle(p, bufPtr, 8);
1563    }
1564    else
1565        putChars(bufPtr, vintrpParamsTbl[p], ::strlen(vintrpParamsTbl[p]));
1566}
1567
1568void GCNDisasmUtils::decodeVOP3Encoding(GCNDisassembler& dasm, size_t codePos,
1569         RelocIter& relocIter, cxuint spacesToAdd,
1570         GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
1571         uint32_t insnCode2, uint32_t literal, FloatLitType displayFloatLits, Flags flags)
1572{
1573    FastOutputBuffer& output = dasm.output;
1574    char* bufStart = output.reserve(170);
1575    char* bufPtr = bufStart;
1576    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4_5)!=0);
1577    const bool isGCN14 = ((arch&ARCH_GCN_1_4_5)!=0);
1578    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
1579    const cxuint opcode = (isGCN12) ? ((insnCode>>16)&0x3ff) : ((insnCode>>17)&0x1ff);
1580   
1581    const cxuint vdst = insnCode&0xff;
1582    const cxuint vsrc0 = insnCode2&0x1ff;
1583    const cxuint vsrc1 = (insnCode2>>9)&0x1ff;
1584    const cxuint vsrc2 = (insnCode2>>18)&0x1ff;
1585    const cxuint sdst = (insnCode>>8)&0x7f;
1586    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
1587    const uint16_t vop3Mode = (gcnInsn.mode&GCN_VOP3_MASK2);
1588   
1589    bool vdstUsed = false;
1590    bool vsrc0Used = false;
1591    bool vsrc1Used = false;
1592    bool vsrc2Used = false;
1593    bool vsrc2CC = false;
1594    cxuint absFlags = 0;
1595    cxuint negFlags = 0;
1596   
1597    if (gcnInsn.encoding == GCNENC_VOP3A && vop3Mode != GCN_VOP3_VOP3P)
1598        absFlags = (insnCode>>8)&7;
1599    // get negation flags from insnCode (VOP3P)
1600    if (vop3Mode != GCN_VOP3_VOP3P)
1601        negFlags = (insnCode2>>29)&7;
1602   
1603    const bool is128Ops = (gcnInsn.mode&0x7000)==GCN_VOP3_DS2_128;
1604    const bool vop3VOPC = (vop3Mode != GCN_VOP3_VOP3P && opcode < 256);
1605   
1606    const cxuint wvSize = (!isGCN15 || (flags&DISASM_WAVE32)==0 ||
1607                    (gcnInsn.mode&GCN_VOP_NOWVSZ)!=0) ? 2 : 1;
1608   
1609    if (mode1 != GCN_VOP_ARG_NONE)
1610    {
1611        vdstUsed = true;
1612        addSpaces(bufPtr, spacesToAdd);
1613       
1614        if ((gcnInsn.mode & GCN_VOP3_NODST)==0)
1615        {
1616            if (vop3VOPC || (gcnInsn.mode&GCN_VOP3_DST_SGPR)!=0)
1617                /* if compares (print DST as SDST) */
1618                decodeGCNOperandNoLit(dasm, vdst, ((gcnInsn.mode&GCN_VOP3_DST_SGPR)==0) ?
1619                                        wvSize:1, bufPtr, arch);
1620            else /* regular instruction */
1621                // for V_MQSAD_U32 SRC2 is 128-bit
1622                decodeGCNVRegOperand(vdst, (is128Ops) ? 4 :
1623                                    ((gcnInsn.mode&GCN_REG_DST_64)?2:1), bufPtr);
1624        }
1625        else
1626            vdstUsed = false;
1627       
1628        if (vdstUsed)
1629            putCommaSpace(bufPtr);
1630        if (gcnInsn.encoding == GCNENC_VOP3B &&
1631            (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC || mode1 == GCN_DST_VCC_VSRC2 ||
1632             mode1 == GCN_S0EQS12)) /* VOP3b */
1633        {
1634            // print SDST operand (VOP3B)
1635            decodeGCNOperandNoLit(dasm, ((insnCode>>8)&0x7f), wvSize, bufPtr, arch);
1636            putCommaSpace(bufPtr);
1637        }
1638        if (vop3Mode != GCN_VOP3_VINTRP)
1639        {
1640            // print negation or abs if supplied
1641            if (negFlags & 1)
1642                *bufPtr++ = '-';
1643            if (absFlags & 1)
1644                putChars(bufPtr, "abs(", 4);
1645            // print VSRC0
1646            if (!isGCN15)
1647                decodeGCNOperandNoLit(dasm, vsrc0, (gcnInsn.mode&GCN_REG_SRC0_64)?2:1,
1648                                   bufPtr, arch, displayFloatLits);
1649            else
1650            {
1651                output.forward(bufPtr-bufStart);
1652                bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, vsrc0,
1653                 (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
1654            }
1655            // closing abs
1656            if (absFlags & 1)
1657                *bufPtr++ = ')';
1658            vsrc0Used = true;
1659        }
1660       
1661        if (vop3Mode == GCN_VOP3_VINTRP)
1662        {
1663            // print negation or abs if supplied
1664            if (negFlags & 2)
1665                *bufPtr++ = '-';
1666            if (absFlags & 2)
1667                putChars(bufPtr, "abs(", 4);
1668            if (mode1 == GCN_P0_P10_P20)
1669                // VINTRP param
1670                decodeVINTRPParam(vsrc1, bufPtr);
1671            else
1672            {
1673                // print VSRC1
1674                if (!isGCN15)
1675                    decodeGCNOperandNoLit(dasm, vsrc1, 1, bufPtr, arch, displayFloatLits);
1676                else
1677                {
1678                    output.forward(bufPtr-bufStart);
1679                    bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, vsrc1,
1680                        1, arch, literal, displayFloatLits);
1681                }
1682            }
1683            if (absFlags & 2)
1684                *bufPtr++ = ')';
1685            // print VINTRP attr
1686            putChars(bufPtr, ", attr", 6);
1687            const cxuint attr = vsrc0&63;
1688            putByteToBuf(attr, bufPtr);
1689            *bufPtr++ = '.';
1690            *bufPtr++ = "xyzw"[((vsrc0>>6)&3)]; // attrchannel
1691           
1692            if ((gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2)
1693            {
1694                putCommaSpace(bufPtr);
1695                // print abs and negation for VSRC2
1696                if (negFlags & 4)
1697                    *bufPtr++ = '-';
1698                if (absFlags & 4)
1699                    putChars(bufPtr, "abs(", 4);
1700                // print VSRC2
1701                if (!isGCN15)
1702                    decodeGCNOperandNoLit(dasm, vsrc2, 1, bufPtr, arch, displayFloatLits);
1703                else
1704                {
1705                    output.forward(bufPtr-bufStart);
1706                    bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, vsrc2,
1707                        1, arch, literal, displayFloatLits);
1708                }
1709                if (absFlags & 4)
1710                    *bufPtr++ = ')';
1711                vsrc2Used = true;
1712            }
1713           
1714            if (vsrc0 & 0x100)
1715                putChars(bufPtr, " high", 5);
1716            vsrc0Used = true;
1717            vsrc1Used = true;
1718        }
1719        else if (mode1 != GCN_SRC12_NONE)
1720        {
1721            putCommaSpace(bufPtr);
1722            // print abs and negation for VSRC1
1723            if (negFlags & 2)
1724                *bufPtr++ = '-';
1725            if (absFlags & 2)
1726                putChars(bufPtr, "abs(", 4);
1727            // print VSRC1
1728            if (!isGCN15)
1729                decodeGCNOperandNoLit(dasm, vsrc1, (gcnInsn.mode&GCN_REG_SRC1_64)?2:1,
1730                        bufPtr, arch, displayFloatLits);
1731            else
1732            {
1733                output.forward(bufPtr-bufStart);
1734                bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, vsrc1,
1735                    (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal, displayFloatLits);
1736            }
1737            if (absFlags & 2)
1738                *bufPtr++ = ')';
1739            /* GCN_DST_VCC - only sdst is used, no vsrc2 */
1740            if (mode1 != GCN_SRC2_NONE && mode1 != GCN_DST_VCC && !vop3VOPC)
1741            {
1742                putCommaSpace(bufPtr);
1743               
1744                if (mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC)
1745                {
1746                    decodeGCNOperandNoLit(dasm, vsrc2, wvSize, bufPtr, arch);
1747                    vsrc2CC = true;
1748                }
1749                else
1750                {
1751                    // print abs and negation for VSRC2
1752                    if (negFlags & 4)
1753                        *bufPtr++ = '-';
1754                    if (absFlags & 4)
1755                        putChars(bufPtr, "abs(", 4);
1756                    // for V_MQSAD_U32 SRC2 is 128-bit
1757                    // print VSRC2
1758                    if (!isGCN15)
1759                        decodeGCNOperandNoLit(dasm, vsrc2, is128Ops ? 4 :
1760                                    (gcnInsn.mode&GCN_REG_SRC2_64)?2:1,
1761                                    bufPtr, arch, displayFloatLits);
1762                    else
1763                    {
1764                        output.forward(bufPtr-bufStart);
1765                        bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter,
1766                                vsrc2, is128Ops ? 4 : (gcnInsn.mode&GCN_REG_SRC2_64)?2:1,
1767                                arch, literal, displayFloatLits);
1768                    }
1769                    if (absFlags & 4)
1770                        *bufPtr++ = ')';
1771                }
1772                vsrc2Used = true;
1773            }
1774            vsrc1Used = true;
1775        }
1776    }
1777    else
1778        addSpaces(bufPtr, spacesToAdd-1);
1779   
1780    uint32_t opselBaseMask = 0;
1781    uint32_t opselMask = 1;
1782    uint32_t opsel = 0;
1783    if (isGCN14 && gcnInsn.encoding != GCNENC_VOP3B)
1784    {
1785        opsel = (insnCode >> 11) & 15;
1786        // print OPSEL
1787        const bool opsel2Bit = (vop3Mode!=GCN_VOP3_VOP3P && vsrc1Used) ||
1788            (vop3Mode==GCN_VOP3_VOP3P && vsrc2Used);
1789        const bool opsel3Bit = (vsrc2Used && vop3Mode!=GCN_VOP3_VOP3P);
1790        if (vop3Mode!=GCN_VOP3_VOP3P)
1791        {
1792            opselMask |= (opsel2Bit?2:0) | (opsel3Bit?4:0) | 8;
1793            opselBaseMask = (15U<<11);
1794        }
1795        else // VOP3P
1796        {
1797            opselMask |= (opsel2Bit?6:2);
1798            opselBaseMask = (7U<<11);
1799        }
1800       
1801        if ((insnCode & (opselMask<<11)) != 0 &&
1802            ((insnCode & opselBaseMask) & ~(opselMask<<11)) == 0)
1803        {
1804            putChars(bufPtr, " op_sel:[", 9);
1805            *bufPtr++ = (insnCode&0x800) ? '1' : '0';
1806            *bufPtr++ = ',';
1807            if (vop3Mode==GCN_VOP3_VOP3P || vsrc1Used)
1808                *bufPtr++ = (insnCode&0x1000) ? '1' : '0';
1809            else
1810                // last bit 14-bit dest (for one operand instr)
1811                *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
1812            // print next opsel if next operand is present
1813            // for VOP3P: VSRC2, non VOP3P - VSRC1
1814            if (vop3Mode!=GCN_VOP3_VOP3P && vsrc1Used)
1815            {
1816                *bufPtr++ = ',';
1817                if (vsrc2Used)
1818                    *bufPtr++ = (insnCode&0x2000) ? '1' : '0';
1819                else
1820                    // last bit 14-bit dest (no third source operand)
1821                    *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
1822            }
1823            else if (vop3Mode==GCN_VOP3_VOP3P && vsrc2Used)
1824            {
1825                *bufPtr++ = ',';
1826                *bufPtr++ = (insnCode&0x2000) ? '1' : '0';
1827            }
1828            // only for VOP3P and VSRC2
1829            if (vsrc2Used && vop3Mode!=GCN_VOP3_VOP3P)
1830            {
1831                *bufPtr++ = ',';
1832                *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
1833            }
1834            *bufPtr++ = ']';
1835        }
1836    }
1837   
1838    // fi VOP3P encoding
1839    if (vop3Mode==GCN_VOP3_VOP3P)
1840    {
1841        // print OP_SEL_HI modifier
1842        cxuint opselHi = ((insnCode2 >> 27) & 3) | (vsrc2Used ? ((insnCode>>12)&4) : 0);
1843        if (opselHi != 3+(vsrc2Used?4:0))
1844        {
1845            putChars(bufPtr, " op_sel_hi:[", 12);
1846            *bufPtr++ = (insnCode2 & (1U<<27)) ? '1' : '0';
1847            *bufPtr++ = ',';
1848            *bufPtr++ = (insnCode2 & (1U<<28)) ? '1' : '0';
1849            if (vsrc2Used)
1850            {
1851                *bufPtr++ = ',';
1852                *bufPtr++ = (insnCode& 0x4000) ? '1' : '0';
1853            }
1854            *bufPtr++ = ']';
1855        }
1856        // print NEG_LO modifier
1857        if ((insnCode2&((3+(vsrc2Used?4:0))<<29)) != 0)
1858        {
1859            putChars(bufPtr, " neg_lo:[", 9);
1860            *bufPtr++ = (insnCode2 & (1U<<29)) ? '1' : '0';
1861            *bufPtr++ = ',';
1862            *bufPtr++ = (insnCode2 & (1U<<30)) ? '1' : '0';
1863            if (vsrc2Used)
1864            {
1865                *bufPtr++ = ',';
1866                *bufPtr++ = (insnCode2 & (1U<<31)) ? '1' : '0';
1867            }
1868            *bufPtr++ = ']';
1869        }
1870        // print NEG_HI modifier
1871        if ((insnCode & ((3+(vsrc2Used?4:0))<<8)) != 0)
1872        {
1873            putChars(bufPtr, " neg_hi:[", 9);
1874            *bufPtr++ = (insnCode & (1U<<8)) ? '1' : '0';
1875            *bufPtr++ = ',';
1876            *bufPtr++ = (insnCode & (1U<<9)) ? '1' : '0';
1877            if (vsrc2Used)
1878            {
1879                *bufPtr++ = ',';
1880                *bufPtr++ = (insnCode & (1U<<10)) ? '1' : '0';
1881            }
1882            *bufPtr++ = ']';
1883        }
1884    }
1885   
1886    const cxuint omod = (insnCode2>>27)&3;
1887    if (vop3Mode != GCN_VOP3_VOP3P && omod != 0)
1888    {
1889        const char* omodStr = (omod==3)?" div:2":(omod==2)?" mul:4":" mul:2";
1890        putChars(bufPtr, omodStr, 6);
1891    }
1892   
1893    const bool clamp = (!isGCN12 && gcnInsn.encoding == GCNENC_VOP3A &&
1894            (insnCode&0x800) != 0) || (isGCN12 && (insnCode&0x8000) != 0);
1895    if (clamp)
1896        putChars(bufPtr, " clamp", 6);
1897   
1898    /* print unused values of parts if not values are not default */
1899    if (!vdstUsed && vdst != 0)
1900    {
1901        putChars(bufPtr, " dst=", 5);
1902        bufPtr += itocstrCStyle(vdst, bufPtr, 6, 16);
1903    }
1904   
1905    if (!vsrc0Used)
1906    {
1907        if (vsrc0 != 0)
1908        {
1909            putChars(bufPtr, " src0=", 6);
1910            bufPtr += itocstrCStyle(vsrc0, bufPtr, 6, 16);
1911        }
1912        if (absFlags & 1)
1913            putChars(bufPtr, " abs0", 5);
1914        if ((insnCode2 & (1U<<29)) != 0)
1915            putChars(bufPtr, " neg0", 5);
1916    }
1917    if (!vsrc1Used)
1918    {
1919        if (vsrc1 != 0)
1920        {
1921            putChars(bufPtr, " vsrc1=", 7);
1922            bufPtr += itocstrCStyle(vsrc1, bufPtr, 6, 16);
1923        }
1924        if (absFlags & 2)
1925            putChars(bufPtr, " abs1", 5);
1926        if ((insnCode2 & (1U<<30)) != 0)
1927            putChars(bufPtr, " neg1", 5);
1928    }
1929    if (!vsrc2Used)
1930    {
1931        if (vsrc2 != 0)
1932        {
1933            putChars(bufPtr, " vsrc2=", 7);
1934            bufPtr += itocstrCStyle(vsrc2, bufPtr, 6, 16);
1935        }
1936        if (absFlags & 4)
1937            putChars(bufPtr, " abs2", 5);
1938        if ((insnCode2 & (1U<<31)) != 0)
1939            putChars(bufPtr, " neg2", 5);
1940    }
1941   
1942    // unused op_sel field
1943    if (isGCN14 && ((insnCode & opselBaseMask) & ~(opselMask<<11)) != 0 &&
1944        gcnInsn.encoding != GCNENC_VOP3B)
1945    {
1946        putChars(bufPtr, " op_sel=", 8);
1947        bufPtr += itocstrCStyle((insnCode>>11)&15, bufPtr, 6, 16);
1948    }
1949   
1950    const cxuint usedMask = 7 & ~(vsrc2CC?4:0);
1951    /* check whether instruction is this same like VOP2/VOP1/VOPC */
1952    bool isVOP1Word = false; // if can be write in single VOP dword
1953    if (vop3Mode == GCN_VOP3_VINTRP)
1954    {
1955        if (mode1 != GCN_NEW_OPCODE) /* check clamp and abs flags */
1956            isVOP1Word = !((insnCode&(7<<8)) != 0 || (insnCode2&(7<<29)) != 0 ||
1957                    clamp || omod!=0 || ((vsrc1 < 256 && mode1!=GCN_P0_P10_P20) ||
1958                    (mode1==GCN_P0_P10_P20 && vsrc1 >= 256)) ||
1959                    vsrc0 >= 256 || vsrc2 != 0);
1960    }
1961    else if (mode1 != GCN_ARG1_IMM && mode1 != GCN_ARG2_IMM)
1962    {
1963        const bool reqForVOP1Word = omod==0 && ((insnCode2&(usedMask<<29)) == 0);
1964        if (gcnInsn.encoding != GCNENC_VOP3B)
1965        {
1966            /* for VOPC */
1967            if (vop3VOPC && vdst == 106 /* vcc */ && vsrc1 >= 256 && vsrc2 == 0)
1968                isVOP1Word = true;
1969            /* for VOP1 */
1970            else if (vop3Mode == GCN_VOP3_VOP1 && vsrc1 == 0 && vsrc2 == 0)
1971                isVOP1Word = true;
1972            /* for VOP2 */
1973            else if (vop3Mode == GCN_VOP3_VOP2 && ((!vsrc1Used && vsrc1 == 0) || 
1974                /* distinguish for v_read/writelane and other vop2 encoded as vop3 */
1975                (((gcnInsn.mode&GCN_VOP3_SRC1_SGPR)==0) && vsrc1 >= 256) ||
1976                (((gcnInsn.mode&GCN_VOP3_SRC1_SGPR)!=0) && vsrc1 < 256)) &&
1977                ((mode1 != GCN_SRC2_VCC && vsrc2 == 0) ||
1978                (vsrc2 == 106 && mode1 == GCN_SRC2_VCC)))
1979                isVOP1Word = true;
1980            /* check clamp and abs and neg flags */
1981            if ((insnCode&(usedMask<<8)) != 0 || (insnCode2&(usedMask<<29)) != 0 || clamp)
1982                isVOP1Word = false;
1983        }
1984        /* for VOP2 encoded as VOP3b (v_addc....) */
1985        else if (gcnInsn.encoding == GCNENC_VOP3B && vop3Mode == GCN_VOP3_VOP2 &&
1986                vsrc1 >= 256 && sdst == 106 /* vcc */ &&
1987                ((vsrc2 == 106 && mode1 == GCN_DS2_VCC) || 
1988                    (vsrc2 == 0 && mode1 != GCN_DS2_VCC))) /* VOP3b */
1989            isVOP1Word = true;
1990       
1991        if (isVOP1Word && !reqForVOP1Word)
1992            isVOP1Word = false;
1993        if (opsel != 0)
1994            isVOP1Word = false;
1995    }
1996    else // force for v_madmk_f32 and v_madak_f32
1997        isVOP1Word = true;
1998   
1999    if (isVOP1Word) // add vop3 for distinguishing encoding
2000        putChars(bufPtr, " vop3", 5);
2001   
2002    output.forward(bufPtr-bufStart);
2003}
2004
2005void GCNDisasmUtils::decodeVINTRPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2006          GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode)
2007{
2008    FastOutputBuffer& output = dasm.output;
2009    char* bufStart = output.reserve(90);
2010    char* bufPtr = bufStart;
2011    addSpaces(bufPtr, spacesToAdd);
2012    // print DST operand
2013    decodeGCNVRegOperand((insnCode>>18)&0xff, 1, bufPtr);
2014    putCommaSpace(bufPtr);
2015    if ((gcnInsn.mode & GCN_MASK1) == GCN_P0_P10_P20)
2016        // print VINTRP param
2017        decodeVINTRPParam(insnCode&0xff, bufPtr);
2018    else
2019        // or VSRC0 operand
2020        decodeGCNVRegOperand(insnCode&0xff, 1, bufPtr);
2021    putChars(bufPtr, ", attr", 6);
2022    const cxuint attr = (insnCode>>10)&63;
2023    putByteToBuf(attr, bufPtr);
2024    *bufPtr++ = '.';
2025    *bufPtr++ = "xyzw"[((insnCode>>8)&3)]; // attrchannel
2026    output.forward(bufPtr-bufStart);
2027}
2028
2029void GCNDisasmUtils::decodeDSEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2030          GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2031          uint32_t insnCode2)
2032{
2033    FastOutputBuffer& output = dasm.output;
2034    char* bufStart = output.reserve(105);
2035    char* bufPtr = bufStart;
2036    // isGCN12 - true if GCN1.2/GCN1.4, otherwise false (for GCN1.0/1.1/1.5)
2037    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
2038    addSpaces(bufPtr, spacesToAdd);
2039    bool vdstUsed = false;
2040    bool vaddrUsed = false;
2041    bool vdata0Used = false;
2042    bool vdata1Used = false;
2043    const cxuint vaddr = insnCode2&0xff;
2044    const cxuint vdata0 = (insnCode2>>8)&0xff;
2045    const cxuint vdata1 = (insnCode2>>16)&0xff;
2046    const cxuint vdst = insnCode2>>24;
2047   
2048    if (((gcnInsn.mode & GCN_ADDR_SRC) != 0 || (gcnInsn.mode & GCN_ONLYDST) != 0) &&
2049            (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2050    {
2051        /* vdst is dst */
2052        cxuint regsNum = (gcnInsn.mode&GCN_REG_DST_64)?2:1;
2053        if ((gcnInsn.mode&GCN_DS_96) != 0)
2054            regsNum = 3;
2055        if ((gcnInsn.mode&GCN_DS_128) != 0 || (gcnInsn.mode&GCN_DST128) != 0)
2056            regsNum = 4;
2057        // print VDST
2058        decodeGCNVRegOperand(vdst, regsNum, bufPtr);
2059        vdstUsed = true;
2060    }
2061    if ((gcnInsn.mode & GCN_ONLYDST) == 0 && (gcnInsn.mode & GCN_ONLY_SRC) == 0)
2062    {
2063        /// print VADDR
2064        if (vdstUsed)
2065            putCommaSpace(bufPtr);
2066        decodeGCNVRegOperand(vaddr, 1, bufPtr);
2067        vaddrUsed = true;
2068    }
2069   
2070    const uint16_t srcMode = (gcnInsn.mode & GCN_SRCS_MASK);
2071   
2072    if ((gcnInsn.mode & GCN_ONLYDST) == 0 &&
2073        (gcnInsn.mode & (GCN_ADDR_DST|GCN_ADDR_SRC)) != 0 && srcMode != GCN_NOSRC)
2074    {
2075        /* print two vdata */
2076        if (vaddrUsed || vdstUsed)
2077            // comma after previous argument (VDST, VADDR)
2078            putCommaSpace(bufPtr);
2079        // determine number of register for VDATA0
2080        cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
2081        if ((gcnInsn.mode&GCN_DS_96) != 0)
2082            regsNum = 3;
2083        if ((gcnInsn.mode&GCN_DS_128) != 0)
2084            regsNum = 4;
2085        // print VDATA0
2086        decodeGCNVRegOperand(vdata0, regsNum, bufPtr);
2087        vdata0Used = true;
2088        if (srcMode == GCN_2SRCS)
2089        {
2090            putCommaSpace(bufPtr);
2091            // print VDATA1
2092            decodeGCNVRegOperand(vdata1, (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr);
2093            vdata1Used = true;
2094        }
2095    }
2096   
2097    const cxuint offset = (insnCode&0xffff);
2098    // printing offsets (one 16-bit or two 8-bit)
2099    if (offset != 0)
2100    {
2101        if ((gcnInsn.mode & GCN_2OFFSETS) == 0) /* single offset */
2102        {
2103            putChars(bufPtr, " offset:", 8);
2104            bufPtr += itocstrCStyle(offset, bufPtr, 7, 10);
2105        }
2106        else
2107        {
2108            // if two 8-bit offsets (if supplied)
2109            if ((offset&0xff) != 0)
2110            {
2111                putChars(bufPtr, " offset0:", 9);
2112                putByteToBuf(offset&0xff, bufPtr);
2113            }
2114            if ((offset&0xff00) != 0)
2115            {
2116                putChars(bufPtr, " offset1:", 9);
2117                putByteToBuf((offset>>8)&0xff, bufPtr);
2118            }
2119        }
2120    }
2121   
2122    if ((!isGCN12 && (insnCode&0x20000)!=0) || (isGCN12 && (insnCode&0x10000)!=0))
2123        putChars(bufPtr, " gds", 4);
2124   
2125    // print value, if some are not used, but values is not default
2126    if (!vaddrUsed && vaddr != 0)
2127    {
2128        putChars(bufPtr, " vaddr=", 7);
2129        bufPtr += itocstrCStyle(vaddr, bufPtr, 6, 16);
2130    }
2131    if (!vdata0Used && vdata0 != 0)
2132    {
2133        putChars(bufPtr, " vdata0=", 8);
2134        bufPtr += itocstrCStyle(vdata0, bufPtr, 6, 16);
2135    }
2136    if (!vdata1Used && vdata1 != 0)
2137    {
2138        putChars(bufPtr, " vdata1=", 8);
2139        bufPtr += itocstrCStyle(vdata1, bufPtr, 6, 16);
2140    }
2141    if (!vdstUsed && vdst != 0)
2142    {
2143        putChars(bufPtr, " vdst=", 6);
2144        bufPtr += itocstrCStyle(vdst, bufPtr, 6, 16);
2145    }
2146    output.forward(bufPtr-bufStart);
2147}
2148
2149// print DATA FORMAT name table
2150static const char* mtbufDFMTTable[] =
2151{
2152    "invalid", "8", "16", "8_8", "32", "16_16", "10_11_11", "11_11_10",
2153    "10_10_10_2", "2_10_10_10", "8_8_8_8", "32_32", "16_16_16_16", "32_32_32",
2154    "32_32_32_32", "reserved"
2155};
2156
2157// print NUMBER FORMAT name table
2158static const char* mtbufNFMTTable[] =
2159{
2160    "unorm", "snorm", "uscaled", "sscaled",
2161    "uint", "sint", "snorm_ogl", "float"
2162};
2163
2164void GCNDisasmUtils::decodeMUBUFEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2165          GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2166          uint32_t insnCode2)
2167{
2168    FastOutputBuffer& output = dasm.output;
2169    char* bufStart = output.reserve(170);
2170    char* bufPtr = bufStart;
2171    const bool isGCN12 = ((arch&ARCH_GCN_1_2_4_5)!=0);
2172    const bool isGCN14 = ((arch&ARCH_GCN_1_4_5)!=0);
2173    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
2174    const cxuint vaddr = insnCode2&0xff;
2175    const cxuint vdata = (insnCode2>>8)&0xff;
2176    const cxuint srsrc = (insnCode2>>16)&0x1f;
2177    const cxuint soffset = insnCode2>>24;
2178    const GCNInsnMode mode1 = (gcnInsn.mode & GCN_MASK1);
2179    if (mode1 != GCN_ARG_NONE)
2180    {
2181        addSpaces(bufPtr, spacesToAdd);
2182        if (mode1 != GCN_MUBUF_NOVAD)
2183        {
2184            // determine number of regs in VDATA
2185            cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
2186            if ((gcnInsn.mode & GCN_MUBUF_D16)!=0 && isGCN14)
2187                // 16-bit values packed into half of number of registers
2188                dregsNum = (dregsNum+1)>>1;
2189            if (insnCode2 & 0x800000U)
2190                dregsNum++; // tfe
2191            // print VDATA
2192            decodeGCNVRegOperand(vdata, dregsNum, bufPtr);
2193            putCommaSpace(bufPtr);
2194            // determine number of vaddr registers
2195            /* for addr32 - idxen+offen or 1, for addr64 - 2 (idxen and offen is illegal) */
2196            const cxuint aregsNum = ((insnCode & 0x3000U)==0x3000U ||
2197                    /* addr64 only for older GCN than 1.2 */
2198                    (!isGCN12 && (insnCode & 0x8000U)))? 2 : 1;
2199            // print VADDR
2200            decodeGCNVRegOperand(vaddr, aregsNum, bufPtr);
2201            putCommaSpace(bufPtr);
2202        }
2203        // print SRSRC
2204        decodeGCNOperandNoLit(dasm, srsrc<<2, 4, bufPtr, arch);
2205        putCommaSpace(bufPtr);
2206        // print SOFFSET
2207        decodeGCNOperandNoLit(dasm, soffset, 1, bufPtr, arch);
2208    }
2209    else
2210        addSpaces(bufPtr, spacesToAdd-1);
2211   
2212    // print modifiers: (offen and idxen, glc)
2213    if (insnCode & 0x1000U)
2214        putChars(bufPtr, " offen", 6);
2215    if (insnCode & 0x2000U)
2216        putChars(bufPtr, " idxen", 6);
2217    const cxuint offset = insnCode&0xfff;
2218    if (offset != 0)
2219    {
2220        putChars(bufPtr, " offset:", 8);
2221        bufPtr += itocstrCStyle(offset, bufPtr, 7, 10);
2222    }
2223    if (insnCode & 0x4000U)
2224        putChars(bufPtr, " glc", 4);
2225   
2226    // print SLC if supplied
2227    if (!isGCN15)
2228    {
2229        if (((!isGCN12 || gcnInsn.encoding==GCNENC_MTBUF) && (insnCode2 & 0x400000U)!=0) ||
2230            ((isGCN12 && gcnInsn.encoding!=GCNENC_MTBUF) && (insnCode & 0x20000)!=0))
2231            putChars(bufPtr, " slc", 4);
2232    }
2233    else if ((insnCode2 & 0x400000U)!=0)
2234        putChars(bufPtr, " slc", 4);
2235   
2236    if (!isGCN12 && (insnCode & 0x8000U)!=0)
2237        putChars(bufPtr, " addr64", 7);
2238    if (isGCN15 && (insnCode & 0x8000U)!=0)
2239        putChars(bufPtr, " dlc", 4);
2240    if (gcnInsn.encoding!=GCNENC_MTBUF && (insnCode & 0x10000U) != 0)
2241        putChars(bufPtr, " lds", 4);
2242    if (insnCode2 & 0x800000U)
2243        putChars(bufPtr, " tfe", 4);
2244    // routine to decode MTBUF format (include default values)
2245    if (gcnInsn.encoding==GCNENC_MTBUF)
2246    {
2247        if (!isGCN15)
2248        {
2249            const cxuint dfmt = (insnCode>>19)&15;
2250            const cxuint nfmt = (insnCode>>23)&7;
2251            if (dfmt!=1 || nfmt!=0)
2252            {
2253                // in shortened form: format:[DFMT, NFMT]
2254                putChars(bufPtr, " format:[", 9);
2255                if (dfmt!=1)
2256                {
2257                    // print DATA_FORMAT if not default
2258                    const char* dfmtStr = mtbufDFMTTable[dfmt];
2259                    putChars(bufPtr, dfmtStr, ::strlen(dfmtStr));
2260                }
2261                if (dfmt!=1 && nfmt!=0)
2262                    *bufPtr++ = ',';
2263                if (nfmt!=0)
2264                {
2265                    // print NUMBER_FORMAT if not default
2266                    const char* nfmtStr = mtbufNFMTTable[nfmt];
2267                    putChars(bufPtr, nfmtStr, ::strlen(nfmtStr));
2268                }
2269                *bufPtr++ = ']';
2270            }
2271        }
2272        else
2273        {
2274            // GFX10
2275            const cxuint format = (insnCode>>19)&127;
2276            if (format!=0)
2277            {
2278                putChars(bufPtr, " format:", 8);
2279                putByteToBuf(format, bufPtr);
2280            }
2281        }
2282    }
2283    // print value, if some are not used, but values is not default
2284    if (mode1 == GCN_ARG_NONE || mode1 == GCN_MUBUF_NOVAD)
2285    {
2286        if (vaddr != 0)
2287        {
2288            putChars(bufPtr, " vaddr=", 7);
2289            bufPtr += itocstrCStyle(vaddr, bufPtr, 6, 16);
2290        }
2291        if (vdata != 0)
2292        {
2293            putChars(bufPtr, " vdata=", 7);
2294            bufPtr += itocstrCStyle(vdata, bufPtr, 6, 16);
2295        }
2296    }
2297    // also SRSRC and SOFFSET if no argument in instruction
2298    if (mode1 == GCN_ARG_NONE)
2299    {
2300        if (srsrc != 0)
2301        {
2302            putChars(bufPtr, " srsrc=", 7);
2303            bufPtr += itocstrCStyle(srsrc, bufPtr, 6, 16);
2304        }
2305        if (soffset != 0)
2306        {
2307            putChars(bufPtr, " soffset=", 9);
2308            bufPtr += itocstrCStyle(soffset, bufPtr, 6, 16);
2309        }
2310    }
2311    output.forward(bufPtr-bufStart);
2312}
2313
2314void GCNDisasmUtils::decodeMIMGEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2315         GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2316         uint32_t insnCode2)
2317{
2318    const bool isGCN14 = ((arch&ARCH_GCN_1_4)!=0);
2319    FastOutputBuffer& output = dasm.output;
2320    char* bufStart = output.reserve(170);
2321    char* bufPtr = bufStart;
2322    addSpaces(bufPtr, spacesToAdd);
2323   
2324    const cxuint dmask = (insnCode>>8)&15;
2325    cxuint dregsNum = 4;
2326    // determine register number for VDATA
2327    if ((gcnInsn.mode & GCN_MIMG_VDATA4) == 0)
2328        dregsNum = ((dmask & 1)?1:0) + ((dmask & 2)?1:0) + ((dmask & 4)?1:0) +
2329                ((dmask & 8)?1:0);
2330   
2331    dregsNum = (dregsNum == 0) ? 1 : dregsNum;
2332    if (isGCN14 && (insnCode2 & (1U<<31))!=0)
2333        dregsNum = (dregsNum+1)>>1;
2334    if (insnCode & 0x10000)
2335        dregsNum++; // tfe
2336   
2337    // print VDATA
2338    decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
2339    putCommaSpace(bufPtr);
2340    // print VADDR
2341    decodeGCNVRegOperand(insnCode2&0xff,
2342                 std::max(GCNInsnMode(4), (gcnInsn.mode&GCN_MIMG_VA_MASK)+1), bufPtr);
2343    putCommaSpace(bufPtr);
2344    // print SRSRC
2345    decodeGCNOperandNoLit(dasm, ((insnCode2>>14)&0x7c),
2346                (((insnCode & 0x8000)!=0) && !isGCN14) ? 4: 8, bufPtr, arch);
2347   
2348    const cxuint ssamp = (insnCode2>>21)&0x1f;
2349    if ((gcnInsn.mode & GCN_MIMG_SAMPLE) != 0)
2350    {
2351        putCommaSpace(bufPtr);
2352        // print SSAMP if supplied
2353        decodeGCNOperandNoLit(dasm, ssamp<<2, 4, bufPtr, arch);
2354    }
2355    if (dmask != 1)
2356    {
2357        putChars(bufPtr, " dmask:", 7);
2358        // print value dmask (0-15)
2359        if (dmask >= 10)
2360        {
2361            *bufPtr++ = '1';
2362            *bufPtr++ = '0' + dmask - 10;
2363        }
2364        else
2365            *bufPtr++ = '0' + dmask;
2366    }
2367   
2368    // print other modifiers (unorm, glc, slc, ...)
2369    if (insnCode & 0x1000)
2370        putChars(bufPtr, " unorm", 6);
2371    if (insnCode & 0x2000)
2372        putChars(bufPtr, " glc", 4);
2373    if (insnCode & 0x2000000)
2374        putChars(bufPtr, " slc", 4);
2375    if (insnCode & 0x8000)
2376    {
2377        if (!isGCN14)
2378            putChars(bufPtr, " r128", 5);
2379        else
2380            putChars(bufPtr, " a16", 4);
2381    }
2382    if (insnCode & 0x10000)
2383        putChars(bufPtr, " tfe", 4);
2384    if (insnCode & 0x20000)
2385        putChars(bufPtr, " lwe", 4);
2386    if (insnCode & 0x4000)
2387        putChars(bufPtr, " da", 3);
2388   
2389    if ((arch & ARCH_GCN_1_2_4)!=0 && (insnCode2 & (1U<<31)) != 0)
2390        putChars(bufPtr, " d16", 4);
2391   
2392    // print value, if some are not used, but values is not default
2393    if ((gcnInsn.mode & GCN_MIMG_SAMPLE) == 0 && ssamp != 0)
2394    {
2395        putChars(bufPtr, " ssamp=", 7);
2396        bufPtr += itocstrCStyle(ssamp, bufPtr, 6, 16);
2397    }
2398    output.forward(bufPtr-bufStart);
2399}
2400
2401struct GFX10MIMGDimEntry
2402{
2403    const char *name;
2404    cxuint dwordsNum;
2405    cxuint derivsNum; // deriv dwords num
2406};
2407
2408static const GFX10MIMGDimEntry gfx10MImgDimEntryTbl[8] =
2409{
2410    { "1d", 1, 2 }, { "2d", 2, 4 }, { "3d", 3, 6 }, { "cube", 3, 4 },
2411    { "1d_array", 2, 2 }, { "2d_array", 3, 4 }, { "2d_msaa", 3, 4 },
2412    { "2d_msaa_array", 4, 4 }
2413};
2414
2415void GCNDisasmUtils::decodeMIMGEncodingGFX10(GCNDisassembler& dasm, cxuint spacesToAdd,
2416        GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2417        uint32_t insnCode2, uint32_t insnCode3, uint32_t insnCode4, uint32_t insnCode5)
2418{
2419    FastOutputBuffer& output = dasm.output;
2420    char* bufStart = output.reserve(250);
2421    char* bufPtr = bufStart;
2422    addSpaces(bufPtr, spacesToAdd);
2423   
2424    const cxuint dim = (insnCode>>3)&7;
2425    const cxuint dmask = (insnCode>>8)&15;
2426    cxuint dregsNum = 4;
2427    // determine register number for VDATA
2428    if ((gcnInsn.mode & GCN_MIMG_VDATA4) == 0)
2429        dregsNum = ((dmask & 1)?1:0) + ((dmask & 2)?1:0) + ((dmask & 4)?1:0) +
2430                ((dmask & 8)?1:0);
2431   
2432    if (insnCode2 & (1U<<31))
2433        dregsNum = (dregsNum+1)>>1;
2434    dregsNum = (dregsNum == 0) ? 1 : dregsNum;
2435    if (insnCode & 0x10000)
2436        dregsNum++; // tfe
2437   
2438    const cxuint extraCodes = ((insnCode>>1)&3);
2439    // print VDATA
2440    decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
2441    putCommaSpace(bufPtr);
2442   
2443    // calculate VADDR registers number
2444    cxuint daddrsNum = gfx10MImgDimEntryTbl[dim].dwordsNum;
2445    if ((gcnInsn.mode & GCN_MIMG_VADERIV)!=0)
2446        daddrsNum += gfx10MImgDimEntryTbl[dim].derivsNum;
2447    daddrsNum += ((gcnInsn.mode & GCN_MIMG_VA_MIP)!=0) +
2448                ((gcnInsn.mode & GCN_MIMG_VA_C)!=0) +
2449                ((gcnInsn.mode & GCN_MIMG_VA_CL)!=0) +
2450                ((gcnInsn.mode & GCN_MIMG_VA_L)!=0) +
2451                ((gcnInsn.mode & GCN_MIMG_VA_B)!=0) +
2452                ((gcnInsn.mode & GCN_MIMG_VA_O)!=0);
2453    // print VADDR
2454    if (extraCodes==0)
2455        decodeGCNVRegOperand(insnCode2&0xff, daddrsNum, bufPtr);
2456    else
2457    {
2458        // list of VADDR VGPRs
2459        daddrsNum = std::min(daddrsNum, (extraCodes)*4 + 1);
2460        *bufPtr++ = '[';
2461        decodeGCNVRegOperand(insnCode2&0xff, 1, bufPtr);
2462        *bufPtr++ = ',';
2463        uint32_t vaddrDwords[3] = { insnCode3, insnCode4, insnCode5 };
2464        for (cxuint i = 1; i < daddrsNum && i < 13; i++)
2465        {
2466            decodeGCNVRegOperand((vaddrDwords[(i-1)>>2]>>(((i-1)&3)*8))&0xff, 1, bufPtr);
2467            *bufPtr++ = (i+1 < daddrsNum) ? ',' : ']';
2468        }
2469    }
2470    putCommaSpace(bufPtr);
2471    // print SRSRC
2472    decodeGCNOperandNoLit(dasm, ((insnCode2>>14)&0x7c),
2473                ((insnCode & 0x8000)!=0) ? 4: 8, bufPtr, arch);
2474   
2475    const cxuint ssamp = (insnCode2>>21)&0x1f;
2476    if ((gcnInsn.mode & GCN_MIMG_SAMPLE) != 0)
2477    {
2478        putCommaSpace(bufPtr);
2479        // print SSAMP if supplied
2480        decodeGCNOperandNoLit(dasm, ssamp<<2, 4, bufPtr, arch);
2481    }
2482   
2483    if (dmask != 1)
2484    {
2485        putChars(bufPtr, " dmask:", 7);
2486        // print value dmask (0-15)
2487        if (dmask >= 10)
2488        {
2489            *bufPtr++ = '1';
2490            *bufPtr++ = '0' + dmask - 10;
2491        }
2492        else
2493            *bufPtr++ = '0' + dmask;
2494    }
2495   
2496    {
2497        putChars(bufPtr, " dim:", 5);
2498        const char *dimName = gfx10MImgDimEntryTbl[dim].name;
2499        putChars(bufPtr, dimName, ::strlen(dimName));
2500    }
2501   
2502    if (insnCode & 0x1000)
2503        putChars(bufPtr, " unorm", 6);
2504    if (insnCode & 0x80)
2505        putChars(bufPtr, " dlc", 4);
2506    if (insnCode & 0x2000)
2507        putChars(bufPtr, " glc", 4);
2508    if (insnCode & 0x2000000)
2509        putChars(bufPtr, " slc", 4);
2510    if (insnCode & 0x8000)
2511        putChars(bufPtr, " r128", 5);
2512    if (insnCode & 0x10000)
2513        putChars(bufPtr, " tfe", 4);
2514    if (insnCode & 0x20000)
2515        putChars(bufPtr, " lwe", 4);
2516    if (insnCode2 & (1U<<31))
2517        putChars(bufPtr, " d16", 4);
2518   
2519    // print value, if some are not used, but values is not default
2520    if ((gcnInsn.mode & GCN_MIMG_SAMPLE) == 0 && ssamp != 0)
2521    {
2522        putChars(bufPtr, " ssamp=", 7);
2523        bufPtr += itocstrCStyle(ssamp, bufPtr, 6, 16);
2524    }
2525    output.forward(bufPtr-bufStart);
2526}
2527
2528void GCNDisasmUtils::decodeEXPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2529            GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2530            uint32_t insnCode2)
2531{
2532    FastOutputBuffer& output = dasm.output;
2533    char* bufStart = output.reserve(100);
2534    char* bufPtr = bufStart;
2535    addSpaces(bufPtr, spacesToAdd);
2536    /* export target */
2537    const cxuint target = (insnCode>>4)&63;
2538    if (target >= 32)
2539    {
2540        // print paramXX
2541        putChars(bufPtr, "param", 5);
2542        const cxuint tpar = target-32;
2543        const cxuint digit2 = tpar/10;
2544        if (digit2 != 0)
2545            *bufPtr++ = '0' + digit2;
2546        *bufPtr++ = '0' + tpar - 10*digit2;
2547    }
2548    else if (target >= 12 && target <= 15)
2549    {
2550        // print posX
2551        putChars(bufPtr, "pos0", 4);
2552        bufPtr[-1] = '0' + target-12;
2553    }
2554    else if (target < 8)
2555    {
2556        // print mrtX
2557        putChars(bufPtr, "mrt0", 4);
2558        bufPtr[-1] = '0' + target;
2559    }
2560    else if (target == 8)
2561        putChars(bufPtr, "mrtz", 4);
2562    else if (target == 9)
2563        putChars(bufPtr, "null", 4);
2564    else
2565    {
2566        /* reserved */
2567        putChars(bufPtr, "ill_", 4);
2568        const cxuint digit2 = target/10U;
2569        *bufPtr++ = '0' + digit2;
2570        *bufPtr++ = '0' + target - 10U*digit2;
2571    }
2572   
2573    /* print vdata registers */
2574    cxuint vsrcsUsed = 0;
2575    for (cxuint i = 0; i < 4; i++)
2576    {
2577        putCommaSpace(bufPtr);
2578        if (insnCode & (1U<<i))
2579        {
2580            if ((insnCode&0x400)==0)
2581            {
2582                decodeGCNVRegOperand((insnCode2>>(i<<3))&0xff, 1, bufPtr);
2583                vsrcsUsed |= 1<<i;
2584            }
2585            else
2586            {
2587                // if compr=1
2588                decodeGCNVRegOperand(((i>=2)?(insnCode2>>8):insnCode2)&0xff, 1, bufPtr);
2589                vsrcsUsed |= 1U<<(i>>1);
2590            }
2591        }
2592        else
2593            putChars(bufPtr, "off", 3);
2594    }
2595   
2596    // other modifiers
2597    if (insnCode&0x800)
2598        putChars(bufPtr, " done", 5);
2599    if (insnCode&0x400)
2600        putChars(bufPtr, " compr", 6);
2601    if (insnCode&0x1000)
2602        putChars(bufPtr, " vm", 3);
2603   
2604    // print value, if some are not used, but values is not default
2605    for (cxuint i = 0; i < 4; i++)
2606    {
2607        const cxuint val = (insnCode2>>(i<<3))&0xff;
2608        if ((vsrcsUsed&(1U<<i))==0 && val!=0)
2609        {
2610            putChars(bufPtr, " vsrc0=", 7);
2611            bufPtr[-2] += i; // number
2612            bufPtr += itocstrCStyle(val, bufPtr, 6, 16);
2613        }
2614    }
2615    output.forward(bufPtr-bufStart);
2616}
2617
2618// routine to print FLAT address including 'off' for GCN 1.4
2619void GCNDisasmUtils::printFLATAddr(cxuint flatMode, char*& bufPtr, uint32_t insnCode2,
2620                                   cxuint nullCode)
2621{
2622    const cxuint vaddr = insnCode2&0xff;
2623    if (flatMode == 0)
2624        decodeGCNVRegOperand(vaddr, 2 , bufPtr); // addr
2625    else if (flatMode == GCN_FLAT_GLOBAL)
2626        decodeGCNVRegOperand(vaddr,
2627                // if off in SADDR, then single VGPR offset
2628                ((insnCode2>>16)&0x7f) == nullCode ? 2 : 1, bufPtr); // addr
2629    else if (flatMode == GCN_FLAT_SCRATCH)
2630    {
2631        if (((insnCode2>>16)&0x7f) == nullCode)
2632            decodeGCNVRegOperand(vaddr, 1, bufPtr); // addr
2633        else // no vaddr
2634            putChars(bufPtr, "off", 3);
2635    }
2636}
2637
2638void GCNDisasmUtils::decodeFLATEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
2639            GPUArchMask arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
2640            uint32_t insnCode2)
2641{
2642    const bool isGCN14 = ((arch&ARCH_GCN_1_4)!=0);
2643    const bool isGCN15 = ((arch&ARCH_GCN_1_5)!=0);
2644    FastOutputBuffer& output = dasm.output;
2645    char* bufStart = output.reserve(150);
2646    char* bufPtr = bufStart;
2647    addSpaces(bufPtr, spacesToAdd);
2648    bool vdstUsed = false;
2649    bool vdataUsed = false;
2650    bool saddrUsed = false;
2651    const cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
2652    /// cmpswap store only to half of number of data registers
2653    cxuint dstRegsNum = ((gcnInsn.mode & GCN_CMPSWAP)!=0) ? (dregsNum>>1) :  dregsNum;
2654    const cxuint flatMode = gcnInsn.mode & GCN_FLAT_MODEMASK;
2655    // add tfe extra register if needed
2656    dstRegsNum = (!isGCN14 && !isGCN15 && (insnCode2 & 0x800000U)) ?
2657                        dstRegsNum+1 : dstRegsNum;
2658   
2659    const cxuint nullCode = isGCN15 ? 0x7d : 0x7f;
2660    bool printAddr = false;
2661    if ((gcnInsn.mode & GCN_FLAT_ADST) == 0)
2662    {
2663        vdstUsed = true;
2664        // print VDST
2665        decodeGCNVRegOperand(insnCode2>>24, dstRegsNum, bufPtr);
2666        putCommaSpace(bufPtr);
2667        printFLATAddr(flatMode, bufPtr, insnCode2, nullCode);
2668        printAddr = true;
2669    }
2670    else
2671    {
2672        /* two vregs, because 64-bitness stored in PTR32 mode (at runtime) */
2673        printFLATAddr(flatMode, bufPtr, insnCode2, nullCode);
2674        printAddr = true;
2675        if ((gcnInsn.mode & GCN_FLAT_NODST) == 0)
2676        {
2677            vdstUsed = true;
2678            putCommaSpace(bufPtr);
2679            // print VDST
2680            decodeGCNVRegOperand(insnCode2>>24, dstRegsNum, bufPtr);
2681        }
2682    }
2683   
2684    if ((gcnInsn.mode & GCN_FLAT_NODATA) == 0) /* print data */
2685    {
2686        vdataUsed = true;
2687        putCommaSpace(bufPtr);
2688        // print DATA field
2689        decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
2690    }
2691   
2692    if (flatMode != 0 && printAddr)
2693    {
2694        // if GLOBAL_ or SCRATCH_
2695        putCommaSpace(bufPtr);
2696        cxuint saddr = (insnCode2>>16)&0x7f;
2697        if ((isGCN14 && (saddr&0x7f) != 0x7f) || (isGCN15 && (saddr&0x7f) != 0x7d))
2698            // print SADDR (GCN 1.4)
2699            decodeGCNOperandNoLit(dasm, saddr, flatMode == GCN_FLAT_SCRATCH ? 1 : 2,
2700                        bufPtr, arch, FLTLIT_NONE);
2701        else // off
2702            putChars(bufPtr, "off", 3);
2703        saddrUsed = true;
2704    }
2705   
2706    // get inst_offset, with sign if FLAT_SCRATCH, FLAT_GLOBAL
2707    const cxuint offsetMask = isGCN15 ? 0x7ff : 0xfff;
2708    const cxint instOffset = (flatMode != 0 && (insnCode&0x1000) != 0 && !isGCN15) ?
2709                -4096+(insnCode&offsetMask) : insnCode&offsetMask;
2710    if ((isGCN14 || isGCN15) && instOffset != 0)
2711    {
2712        putChars(bufPtr, " inst_offset:", 13);
2713        bufPtr += itocstrCStyle(instOffset, bufPtr, 7, 10);
2714    }
2715   
2716    // print other modifers
2717    if (isGCN14 && (insnCode & 0x2000U))
2718        putChars(bufPtr, " lds", 4);
2719    if (isGCN15 && (insnCode & 0x1000U))
2720        putChars(bufPtr, " dlc", 4);
2721    if (insnCode & 0x10000U)
2722        putChars(bufPtr, " glc", 4);
2723    if (insnCode & 0x20000U)
2724        putChars(bufPtr, " slc", 4);
2725    if (insnCode2 & 0x800000U)
2726    {
2727        if (!isGCN14 && !isGCN15)
2728            putChars(bufPtr, " tfe", 4);
2729        else
2730            // if GCN 1.4 this bit is NV
2731            putChars(bufPtr, " nv", 3);
2732    }
2733   
2734    // print value, if some are not used, but values is not default
2735    if (!vdataUsed && ((insnCode2>>8)&0xff) != 0)
2736    {
2737        putChars(bufPtr, " vdata=", 7);
2738        bufPtr += itocstrCStyle((insnCode2>>8)&0xff, bufPtr, 6, 16);
2739    }
2740    if (!vdstUsed && (insnCode2>>24) != 0)
2741    {
2742        putChars(bufPtr, " vdst=", 6);
2743        bufPtr += itocstrCStyle(insnCode2>>24, bufPtr, 6, 16);
2744    }
2745    if ((flatMode != 0 && !saddrUsed && ((insnCode>>16)&0xff) != 0) ||
2746        (isGCN15 && flatMode==0 && !saddrUsed && ((insnCode2>>16)&0x7f) != 0x7d))
2747    {
2748        putChars(bufPtr, " saddr=", 7);
2749        bufPtr += itocstrCStyle((insnCode2>>16)&0xff, bufPtr, 6, 16);
2750    }
2751   
2752    output.forward(bufPtr-bufStart);
2753}
Note: See TracBrowser for help on using the repository browser.