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

Last change on this file since 4135 was 4135, checked in by matszpk, 6 months ago

CLRadeonExtender: Asm: Move GCN encoding and decoding stuff to separate source codes.

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