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

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

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

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