Changeset 4135 in CLRX


Ignore:
Timestamp:
May 10, 2018, 3:23:39 PM (3 months ago)
Author:
matszpk
Message:

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

Location:
CLRadeonExtender/trunk/amdasm
Files:
4 added
3 edited

Legend:

Unmodified
Added
Removed
  • CLRadeonExtender/trunk/amdasm/CMakeLists.txt

    r4134 r4135  
    3838        DisasmGallium.cpp
    3939        DisasmROCm.cpp
     40        GCNAsmEncode1.cpp
     41        GCNAsmEncode2.cpp
    4042        GCNAsmHelpers.cpp
    4143        GCNAssembler.cpp
    4244        GCNDisasm.cpp
     45        GCNDisasmDecode.cpp
    4346        GCNInstructions.cpp)
    4447
  • CLRadeonExtender/trunk/amdasm/GCNAssembler.cpp

    r4114 r4135  
    345345{ }
    346346
    347 namespace CLRX
    348 {
    349 
    350 static const uint32_t constImmFloatLiterals[9] =
    351 {
    352     0x3f000000, 0xbf000000, 0x3f800000, 0xbf800000,
    353     0x40000000, 0xc0000000, 0x40800000, 0xc0800000, 0x3e22f983
    354 };
    355 
    356 // used while converting 32-bit SOPx encoding to 64-bit SOPx encoding
    357 static void tryPromoteConstImmToLiteral(GCNOperand& src0Op, uint16_t arch)
    358 {
    359     if (!src0Op.range.isRegVar() && src0Op.range.start>=128 && src0Op.range.start<=208)
    360     {
    361         // convert integer const immediates
    362         src0Op.value = src0Op.range.start<193? src0Op.range.start-128 :
    363                 192-src0Op.range.start;
    364         src0Op.range.start = 255;
    365     }
    366     else if (!src0Op.range.isRegVar() &&
    367             ((src0Op.range.start>=240 && src0Op.range.start<248) ||
    368              ((arch&ARCH_GCN_1_2_4)!=0 && src0Op.range.start==248)))
    369     {
    370         // floating point immediates to literal
    371         src0Op.value = constImmFloatLiterals[src0Op.range.start-240];
    372         src0Op.range.start = 255;
    373     }
    374 }
    375 
    376 // check whether reg range can be equal (regvar and registers)
    377 static inline bool regRangeCanEqual(const RegRange& r1, const RegRange& r2)
    378 {
    379     return r1.regVar==r2.regVar && r1.start==r2.start;
    380 }
    381 
    382 bool GCNAsmUtils::parseSOP2Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    383                   const char* instrPlace, const char* linePtr, uint16_t arch,
    384                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    385                   GCNEncSize gcnEncSize)
    386 {
    387     bool good = true;
    388     RegRange dstReg(0, 0);
    389     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    390    
    391     if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
    392     {
    393         // parse SDST (SGPR)
    394         gcnAsm->setCurrentRVU(0);
    395         good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    396                    (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
    397                    INSTROP_SYMREGRANGE|INSTROP_WRITE);
    398         if (!skipRequiredComma(asmr, linePtr))
    399             return false;
    400     }
    401    
    402     std::unique_ptr<AsmExpression> src0Expr, src1Expr;
    403     // parse SRC0 (can be SGPR or scalar source)
    404     GCNOperand src0Op{};
    405     gcnAsm->setCurrentRVU(1);
    406     good &= parseOperand(asmr, linePtr, src0Op, &src0Expr, arch,
    407              (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
    408                          INSTROP_READ, GCNFIELD_SSRC0);
    409     if (!skipRequiredComma(asmr, linePtr))
    410         return false;
    411     GCNOperand src1Op{};
    412     // parse SRC1 (can be SGPR or scalar source)
    413     gcnAsm->setCurrentRVU(2);
    414     good &= parseOperand(asmr, linePtr, src1Op, &src1Expr, arch,
    415              (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
    416              (src0Op.range.isVal(255) ? INSTROP_ONLYINLINECONSTS : 0)|INSTROP_READ,
    417              GCNFIELD_SSRC1);
    418    
    419     /// if errors
    420     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    421         return false;
    422    
    423     if (gcnEncSize==GCNEncSize::BIT64)
    424     {
    425         // try to promote constant immediate to literal
    426         tryPromoteConstImmToLiteral(src0Op, arch);
    427         tryPromoteConstImmToLiteral(src1Op, arch);
    428     }
    429     // put data
    430     cxuint wordsNum = 1;
    431     uint32_t words[2];
    432     SLEV(words[0], 0x80000000U | (uint32_t(gcnInsn.code1)<<23) | src0Op.range.bstart() |
    433             (src1Op.range.bstart()<<8) | uint32_t(dstReg.bstart())<<16);
    434     if (src0Op.range.isVal(255) || src1Op.range.isVal(255))
    435     {
    436         // put literal value
    437         if (src0Expr==nullptr && src1Expr==nullptr)
    438             SLEV(words[1], src0Op.range.isVal(255) ? src0Op.value : src1Op.value);
    439         else    // zero if unresolved value
    440             SLEV(words[1], 0);
    441         wordsNum++;
    442     }
    443     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    444         return false;
    445     // set expression targets to resolving later
    446     if (src0Expr!=nullptr)
    447         src0Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    448                       output.size()));
    449     else if (src1Expr!=nullptr)
    450         src1Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    451                       output.size()));
    452    
    453     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    454             reinterpret_cast<cxbyte*>(words + wordsNum));
    455     // prevent freeing expressions
    456     src0Expr.release();
    457     src1Expr.release();
    458     // update SGPR counting and VCC usage (regflags)
    459     if (dstReg && !dstReg.isRegVar())
    460     {
    461         updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    462         updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    463     }
    464     if (src0Op.range && !src0Op.range.isRegVar())
    465         updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    466     if (src1Op.range && !src1Op.range.isRegVar())
    467         updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
    468     return true;
    469 }
    470 
    471 bool GCNAsmUtils::parseSOP1Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    472                   const char* instrPlace, const char* linePtr, uint16_t arch,
    473                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    474                   GCNEncSize gcnEncSize)
    475 {
    476     bool good = true;
    477     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    478     RegRange dstReg(0, 0);
    479    
    480     if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
    481     {
    482         // parse SDST (SGPR)
    483         gcnAsm->setCurrentRVU(0);
    484         good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    485                        (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
    486                        INSTROP_SYMREGRANGE|INSTROP_WRITE);
    487         if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
    488             if (!skipRequiredComma(asmr, linePtr))
    489                 return false;
    490     }
    491    
    492     GCNOperand src0Op{};
    493     std::unique_ptr<AsmExpression> src0Expr;
    494     if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
    495     {
    496         // parse SRC0 (can be SGPR or source scalar, constant or literal)
    497         gcnAsm->setCurrentRVU(1);
    498         good &= parseOperand(asmr, linePtr, src0Op, &src0Expr, arch,
    499                  (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
    500                          INSTROP_READ, GCNFIELD_SSRC0);
    501     }
    502    
    503     /// if errors
    504     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    505         return false;
    506    
    507     if (gcnEncSize==GCNEncSize::BIT64)
    508         // try to promote constant immediate to literal
    509         tryPromoteConstImmToLiteral(src0Op, arch);
    510     cxuint wordsNum = 1;
    511     uint32_t words[2];
    512     // put instruction word
    513     SLEV(words[0], 0xbe800000U | (uint32_t(gcnInsn.code1)<<8) | src0Op.range.bstart() |
    514             uint32_t(dstReg.bstart())<<16);
    515     if (src0Op.range.start==255)
    516     {
    517         // put literal
    518         if (src0Expr==nullptr)
    519             SLEV(words[1], src0Op.value);
    520         else    // zero if unresolved value
    521             SLEV(words[1], 0);
    522         wordsNum++;
    523     }
    524     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    525         return false;
    526     // set expression targets
    527     if (src0Expr!=nullptr)
    528         src0Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    529                       output.size()));
    530    
    531     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    532             reinterpret_cast<cxbyte*>(words + wordsNum));
    533     // prevent freeing expressions
    534     src0Expr.release();
    535     // update SGPR counting and VCC usage (regflags)
    536     if (dstReg && !dstReg.isRegVar())
    537     {
    538         updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    539         updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    540     }
    541     if (src0Op.range && !src0Op.range.isRegVar())
    542         updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    543     return true;
    544 }
    545 
    546 // hwreg names sorted by names
    547 static const std::pair<const char*, cxuint> hwregNamesMap[] =
    548 {
    549     { "gpr_alloc", 5 },
    550     { "hw_id", 4 },
    551     { "ib_dbg0", 12 },
    552     { "ib_dbg1", 13 },
    553     { "ib_sts", 7 },
    554     { "inst_dw0", 10 },
    555     { "inst_dw1", 11 },
    556     { "lds_alloc", 6 },
    557     { "mode", 1 },
    558     { "pc_hi", 9 },
    559     { "pc_lo", 8 },
    560     { "status", 2 },
    561     { "trapsts", 3 }
    562 };
    563 
    564 static const size_t hwregNamesMapSize = sizeof(hwregNamesMap) /
    565             sizeof(std::pair<const char*, uint16_t>);
    566 
    567 // update SGPR counting and VCC usage (regflags) for GCN 1.4 (VEGA)
    568 static const std::pair<const char*, cxuint> hwregNamesGCN14Map[] =
    569 {
    570     { "flush_ib", 14 },
    571     { "gpr_alloc", 5 },
    572     { "hw_id", 4 },
    573     { "ib_dbg0", 12 },
    574     { "ib_dbg1", 13 },
    575     { "ib_sts", 7 },
    576     { "inst_dw0", 10 },
    577     { "inst_dw1", 11 },
    578     { "lds_alloc", 6 },
    579     { "mode", 1 },
    580     { "pc_hi", 9 },
    581     { "pc_lo", 8 },
    582     { "sh_mem_bases", 15 },
    583     { "sq_shader_tba_hi", 17 },
    584     { "sq_shader_tba_lo", 16 },
    585     { "sq_shader_tma_hi", 19 },
    586     { "sq_shader_tma_lo", 18 },
    587     { "status", 2 },
    588     { "trapsts", 3 }
    589 };
    590 
    591 static const size_t hwregNamesGCN14MapSize = sizeof(hwregNamesGCN14Map) /
    592             sizeof(std::pair<const char*, uint16_t>);
    593 
    594 bool GCNAsmUtils::parseSOPKEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    595                   const char* instrPlace, const char* linePtr, uint16_t arch,
    596                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    597                   GCNEncSize gcnEncSize)
    598 {
    599     const char* end = asmr.line+asmr.lineSize;
    600     bool good = true;
    601     RegRange dstReg(0, 0);
    602     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    603     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    604    
    605     gcnAsm->setCurrentRVU(0);
    606     bool doWrite = (gcnInsn.mode&GCN_MASK1) != GCN_DST_SRC &&
    607             ((gcnInsn.mode&GCN_MASK1) != GCN_IMM_REL);
    608     if ((gcnInsn.mode & GCN_IMM_DST) == 0)
    609     {
    610         // parse SDST (SGPR)
    611         good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    612                    (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
    613                    INSTROP_SYMREGRANGE|
    614                    (doWrite ? INSTROP_WRITE : INSTROP_READ));
    615         if (!skipRequiredComma(asmr, linePtr))
    616             return false;
    617     }
    618    
    619     uint16_t imm16 = 0;
    620     std::unique_ptr<AsmExpression> imm16Expr;
    621    
    622     if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL)
    623     {
    624         // parse relative address
    625         uint64_t value = 0;
    626         if (!getJumpValueArg(asmr, value, imm16Expr, linePtr))
    627             return false;
    628         if (imm16Expr==nullptr)
    629         {
    630             // if resolved at this time
    631             int64_t offset = (int64_t(value)-int64_t(output.size())-4);
    632             if (offset & 3)
    633                 ASM_NOTGOOD_BY_ERROR(linePtr, "Jump is not aligned to word!")
    634             offset >>= 2;
    635             if (offset > INT16_MAX || offset < INT16_MIN)
    636                 ASM_NOTGOOD_BY_ERROR(linePtr, "Jump out of range")
    637             imm16 = offset;
    638             // add codeflow entry
    639             if (good)
    640             {
    641                 asmr.sections[asmr.currentSection].addCodeFlowEntry({
    642                     size_t(asmr.currentOutPos), size_t(value),
    643                     (isGCN14 && gcnInsn.code1==21) ? AsmCodeFlowType::CALL :
    644                             AsmCodeFlowType::CJUMP });
    645             }
    646         }
    647     }
    648     else if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_SREG)
    649     {
    650         // parse hwreg: hwreg(HWREG, bitstart, bitsize)
    651         skipSpacesToEnd(linePtr, end);
    652         char name[20];
    653         const char* funcNamePlace = linePtr;
    654         if (!getNameArg(asmr, 20, name, linePtr, "function name", true))
    655             return false;
    656         toLowerString(name);
    657         skipSpacesToEnd(linePtr, end);
    658         // if not hwreg
    659         if (::strcmp(name, "hwreg")!=0 || linePtr==end || *linePtr!='(')
    660             ASM_FAIL_BY_ERROR(funcNamePlace, "Expected hwreg function")
    661         ++linePtr;
    662         skipSpacesToEnd(linePtr, end);
    663         cxuint hwregId = 0;
    664         if (linePtr == end || *linePtr!='@')
    665         {
    666             // parse hwreg by name
    667             const char* hwregNamePlace = linePtr;
    668             // choose hwReg names map
    669             const size_t regMapSize = isGCN14 ? hwregNamesGCN14MapSize : hwregNamesMapSize;
    670             const std::pair<const char*, cxuint>* regMap = isGCN14 ?
    671                         hwregNamesGCN14Map : hwregNamesMap;
    672             good &= getEnumeration(asmr, linePtr, "HWRegister",
    673                         regMapSize, regMap, hwregId, "hwreg_");
    674             if (good && (arch & ARCH_GCN_1_2_4) == 0 && hwregId == 13)
    675                 // if ib_dgb1 in not GCN 1.2
    676                 ASM_NOTGOOD_BY_ERROR(hwregNamePlace, "Unknown HWRegister")
    677         }
    678         else
    679         {
    680             // parametrization (if preceded by '@')
    681             linePtr++;
    682             good &= parseImm(asmr, linePtr, hwregId, nullptr, 6, WS_UNSIGNED);
    683         }
    684        
    685         if (!skipRequiredComma(asmr, linePtr))
    686             return false;
    687         uint64_t arg2Value = 0;
    688         skipSpacesToEnd(linePtr, end);
    689         const char* funcArg2Place = linePtr;
    690        
    691         // second argument of hwreg
    692         if (getAbsoluteValueArg(asmr, arg2Value, linePtr, true))
    693         {
    694             if (arg2Value >= 32)
    695                 asmr.printWarning(funcArg2Place, "Second argument out of range (0-31)");
    696         }
    697         else
    698             good = false;
    699        
    700         if (!skipRequiredComma(asmr, linePtr))
    701             return false;
    702         uint64_t arg3Value = 0;
    703         skipSpacesToEnd(linePtr, end);
    704         const char* funcArg3Place = linePtr;
    705        
    706         // second argument of hwreg
    707         if (getAbsoluteValueArg(asmr, arg3Value, linePtr, true))
    708         {
    709             if (arg3Value >= 33 || arg3Value < 1)
    710                 asmr.printWarning(funcArg3Place, "Third argument out of range (1-32)");
    711         }
    712         else
    713             good = false;
    714        
    715         skipSpacesToEnd(linePtr, end);
    716         if (linePtr==end || *linePtr!=')')
    717             ASM_FAIL_BY_ERROR(linePtr, "Unterminated hwreg function")
    718         ++linePtr;
    719         imm16 = hwregId | (arg2Value<<6) | ((arg3Value-1)<<11);
    720     }
    721     else // otherwise we parse expression
    722         good &= parseImm(asmr, linePtr, imm16, &imm16Expr);
    723    
    724     uint32_t imm32 = 0;
    725     std::unique_ptr<AsmExpression> imm32Expr;
    726     if (gcnInsn.mode & GCN_IMM_DST)
    727     {
    728         // parse SDST as immediate or next source
    729         if (!skipRequiredComma(asmr, linePtr))
    730             return false;
    731         if (gcnInsn.mode & GCN_SOPK_CONST)
    732             good &= parseImm(asmr, linePtr, imm32, &imm32Expr);
    733         else
    734             good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    735                    (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SDST, true,
    736                    INSTROP_SYMREGRANGE|INSTROP_READ); // new field!
    737     }
    738    
    739     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    740         return false;
    741    
    742     const cxuint wordsNum = (gcnInsn.mode & GCN_SOPK_CONST) ? 2 : 1;
    743     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    744         return false;
    745    
    746     // put data (instruction words)
    747     uint32_t words[2];
    748     SLEV(words[0], 0xb0000000U | imm16 | (uint32_t(dstReg.bstart())<<16) |
    749                 uint32_t(gcnInsn.code1)<<23);
    750     if (wordsNum==2)
    751         SLEV(words[1], imm32);
    752    
    753     // setting expresion targets (for immediates)
    754     if (imm32Expr!=nullptr)
    755         imm32Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    756                            output.size()));
    757     if (imm16Expr!=nullptr)
    758         imm16Expr->setTarget(AsmExprTarget(((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL) ?
    759                 GCNTGT_SOPJMP : GCNTGT_SOPKSIMM16, asmr.currentSection, output.size()));
    760    
    761     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    762             reinterpret_cast<cxbyte*>(words + wordsNum));
    763     /// prevent freeing expression
    764     imm32Expr.release();
    765     imm16Expr.release();
    766     // update SGPR counting and VCC usage (regflags)
    767     if (dstReg && !dstReg.isRegVar() && doWrite && (gcnInsn.mode & GCN_IMM_DST)==0)
    768         updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    769     if (dstReg && !dstReg.isRegVar())
    770         updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    771     return true;
    772 }
    773 
    774 bool GCNAsmUtils::parseSOPCEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    775                   const char* instrPlace, const char* linePtr, uint16_t arch,
    776                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    777                   GCNEncSize gcnEncSize)
    778 {
    779     bool good = true;
    780     std::unique_ptr<AsmExpression> src0Expr, src1Expr;
    781     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    782     GCNOperand src0Op{};
    783    
    784     // parse SRC0 (can be SGPR, source scalar, literal or constant
    785     gcnAsm->setCurrentRVU(0);
    786     good &= parseOperand(asmr, linePtr, src0Op, &src0Expr, arch,
    787              (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
    788                      INSTROP_READ, GCNFIELD_SSRC0);
    789     if (!skipRequiredComma(asmr, linePtr))
    790         return false;
    791     GCNOperand src1Op{};
    792     if ((gcnInsn.mode & GCN_SRC1_IMM) == 0)
    793     {
    794         // parse SRC1 (can be SGPR, source scalar, literal or constant
    795         gcnAsm->setCurrentRVU(1);
    796         good &= parseOperand(asmr, linePtr, src1Op, &src1Expr, arch,
    797                  (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, INSTROP_SSOURCE|INSTROP_SREGS|
    798                  (src0Op.range.start==255 ? INSTROP_ONLYINLINECONSTS : 0)|INSTROP_READ,
    799                          GCNFIELD_SSRC1);
    800     }
    801     else // immediate
    802         good &= parseImm(asmr, linePtr, src1Op.range.start, &src1Expr, 8);
    803    
    804     /// if errors
    805     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    806         return false;
    807    
    808     if (gcnEncSize==GCNEncSize::BIT64)
    809     {
    810         // try to promote constant immediate to literal
    811         tryPromoteConstImmToLiteral(src0Op, arch);
    812         tryPromoteConstImmToLiteral(src1Op, arch);
    813     }
    814     // put data
    815     cxuint wordsNum = 1;
    816     uint32_t words[2];
    817     SLEV(words[0], 0xbf000000U | (uint32_t(gcnInsn.code1)<<16) | src0Op.range.bstart() |
    818             (src1Op.range.bstart()<<8));
    819     if (src0Op.range.start==255 ||
    820         ((gcnInsn.mode & GCN_SRC1_IMM)==0 && src1Op.range.start==255))
    821     {
    822         // put literal
    823         if (src0Expr==nullptr && src1Expr==nullptr)
    824             SLEV(words[1], src0Op.range.isVal(255) ? src0Op.value : src1Op.value);
    825         else    // zero if unresolved value
    826             SLEV(words[1], 0);
    827         wordsNum++;
    828     }
    829     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    830         return false;
    831     // set expression targets
    832     if (src0Expr!=nullptr)
    833         src0Expr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    834                       output.size()));
    835     else if (src1Expr!=nullptr)
    836         src1Expr->setTarget(AsmExprTarget(
    837             ((gcnInsn.mode&GCN_SRC1_IMM)) ? GCNTGT_SOPCIMM8 : GCNTGT_LITIMM,
    838             asmr.currentSection, output.size()));
    839    
    840     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    841             reinterpret_cast<cxbyte*>(words + wordsNum));
    842     // prevent freeing expressions
    843     src0Expr.release();
    844     src1Expr.release();
    845     // update SGPR counting and VCC usage (regflags)
    846     if (src0Op.range && !src0Op.range.isRegVar())
    847         updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    848     if (src1Op.range && !src1Op.range.isRegVar())
    849         updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
    850     return true;
    851 }
    852 
    853 // message names sorted by name
    854 static const std::pair<const char*, uint16_t> sendMessageNamesMap[] =
    855 {
    856     { "gs", 2 },
    857     { "gs_done", 3 },
    858     { "interrupt", 1 },
    859     { "savewave", 4 },
    860     { "sysmsg", 15 },
    861     { "system", 15 }
    862 };
    863 
    864 static const size_t sendMessageNamesMapSize = sizeof(sendMessageNamesMap) /
    865             sizeof(std::pair<const char*, uint16_t>);
    866 
    867 // message names sorted by name for GCN1.4 (VEGA)
    868 static const std::pair<const char*, uint16_t> sendMessageNamesGCN14Map[] =
    869 {
    870     { "early_prim_dealloc", 8 },
    871     { "get_doorbell", 10 },
    872     { "gs", 2 },
    873     { "gs_alloc_req", 9 },
    874     { "gs_done", 3 },
    875     { "halt_waves", 6 },
    876     { "interrupt", 1 },
    877     { "ordered_ps_done", 7 },
    878     { "savewave", 4 },
    879     { "stall_wave_gen", 5 },
    880     { "sysmsg", 15 },
    881     { "system", 15 }
    882 };
    883 
    884 static const size_t sendMessageNamesGCN14MapSize = sizeof(sendMessageNamesGCN14Map) /
    885             sizeof(std::pair<const char*, uint16_t>);
    886 
    887 static const char* sendMsgGSOPTable[] =
    888 { "nop", "cut", "emit", "emit_cut" };
    889 
    890 static const size_t sendMsgGSOPTableSize = sizeof(sendMsgGSOPTable) / sizeof(const char*);
    891 
    892 bool GCNAsmUtils::parseSOPPEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    893                   const char* instrPlace, const char* linePtr, uint16_t arch,
    894                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    895                   GCNEncSize gcnEncSize)
    896 {
    897     const char* end = asmr.line+asmr.lineSize;
    898     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    899     bool good = true;
    900     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    901     if (gcnEncSize==GCNEncSize::BIT64)
    902         ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for SOPP encoding")
    903    
    904     uint16_t imm16 = 0;
    905     std::unique_ptr<AsmExpression> imm16Expr;
    906     switch (gcnInsn.mode&GCN_MASK1)
    907     {
    908         case GCN_IMM_REL:
    909         {
    910             // parse relative address
    911             uint64_t value = 0;
    912             if (!getJumpValueArg(asmr, value, imm16Expr, linePtr))
    913                 return false;
    914             if (imm16Expr==nullptr)
    915             {
    916                 int64_t offset = (int64_t(value)-int64_t(output.size())-4);
    917                 if (offset & 3)
    918                     ASM_NOTGOOD_BY_ERROR(linePtr, "Jump is not aligned to word!")
    919                 offset >>= 2;
    920                 if (offset > INT16_MAX || offset < INT16_MIN)
    921                     ASM_NOTGOOD_BY_ERROR(linePtr, "Jump out of range")
    922                 imm16 = offset;
    923                 Assembler& asmr = gcnAsm->assembler;
    924                 // add codeflow entry
    925                 if (good)
    926                     asmr.sections[asmr.currentSection].addCodeFlowEntry({
    927                         size_t(asmr.currentOutPos), size_t(value),
    928                         gcnInsn.code1==2 ? AsmCodeFlowType::JUMP :
    929                             AsmCodeFlowType::CJUMP });
    930             }
    931             break;
    932         }
    933         case GCN_IMM_LOCKS:
    934         {
    935             /* parse locks for s_waitcnt */
    936             char name[20];
    937             bool haveLgkmCnt = false;
    938             bool haveExpCnt = false;
    939             bool haveVMCnt = false;
    940             imm16 = isGCN14 ? 0xcf7f : 0xf7f;
    941             while (true)
    942             {
    943                 skipSpacesToEnd(linePtr, end);
    944                 const char* funcNamePlace = linePtr;
    945                 name[0] = 0;
    946                 // get function name
    947                 good &= getNameArgS(asmr, 20, name, linePtr, "function name", true);
    948                 toLowerString(name);
    949                
    950                 cxuint bitPos = 0, bitMask = UINT_MAX;
    951                 bool goodCnt = true;
    952                 bool doVMCnt = false;
    953                 // select bitfield for lock
    954                 if (::strcmp(name, "vmcnt")==0)
    955                 {
    956                     if (haveVMCnt)
    957                         asmr.printWarning(funcNamePlace, "vmcnt was already defined");
    958                     bitPos = 0;
    959                     bitMask = isGCN14 ? 63 : 15;
    960                     doVMCnt = haveVMCnt = true;
    961                 }
    962                 else if (::strcmp(name, "lgkmcnt")==0)
    963                 {
    964                     if (haveLgkmCnt)
    965                         asmr.printWarning(funcNamePlace, "lgkmcnt was already defined");
    966                     bitPos = 8;
    967                     bitMask = 15;
    968                     haveLgkmCnt = true;
    969                 }
    970                 else if (::strcmp(name, "expcnt")==0)
    971                 {
    972                     if (haveExpCnt)
    973                         asmr.printWarning(funcNamePlace, "expcnt was already defined");
    974                     bitPos = 4;
    975                     bitMask = 7;
    976                     haveExpCnt = true;
    977                 }
    978                 else
    979                     ASM_NOTGOOD_BY_ERROR1(goodCnt = good, funcNamePlace,
    980                                     "Expected vmcnt, lgkmcnt or expcnt")
    981                
    982                 skipSpacesToEnd(linePtr, end);
    983                 if (linePtr==end || *linePtr!='(')
    984                 {
    985                     if (goodCnt) // only if cnt has been parsed (do not duplicate errors)
    986                         asmr.printError(funcNamePlace, "Expected vmcnt, lgkmcnt or expcnt");
    987                     return false;
    988                 }
    989                 skipCharAndSpacesToEnd(linePtr, end);
    990                 const char* argPlace = linePtr;
    991                 uint64_t value;
    992                 // parse value for lock
    993                 if (getAbsoluteValueArg(asmr, value, linePtr, true))
    994                 {
    995                     if (value > bitMask)
    996                         asmr.printWarning(argPlace, "Value out of range");
    997                     if (!isGCN14 || !doVMCnt)
    998                         imm16 = (imm16 & ~(bitMask<<bitPos)) | ((value&bitMask)<<bitPos);
    999                     else // vmcnt for GFX9
    1000                         imm16 = (imm16 & 0x3ff0) | ((value&15) | ((value&0x30)<<10));
    1001                 }
    1002                 else
    1003                     good = false;
    1004                 skipSpacesToEnd(linePtr, end);
    1005                 if (linePtr==end || *linePtr!=')')
    1006                     ASM_FAIL_BY_ERROR(linePtr, "Unterminated function")
    1007                 // ampersand
    1008                 skipCharAndSpacesToEnd(linePtr, end);
    1009                 if (linePtr==end)
    1010                     break;
    1011                 if (linePtr[0] == '&')
    1012                     ++linePtr;
    1013             }
    1014             break;
    1015         }
    1016         case GCN_IMM_MSGS:
    1017         {
    1018             char name[25];
    1019             const char* funcNamePlace = linePtr;
    1020             if (!getNameArg(asmr, 25, name, linePtr, "function name", true))
    1021                 return false;
    1022             toLowerString(name);
    1023             skipSpacesToEnd(linePtr, end);
    1024             if (::strcmp(name, "sendmsg")!=0 || linePtr==end || *linePtr!='(')
    1025                 ASM_FAIL_BY_ERROR(funcNamePlace, "Expected sendmsg function")
    1026             skipCharAndSpacesToEnd(linePtr, end);
    1027            
    1028             const char* funcArg1Place = linePtr;
    1029             size_t sendMessage = 0;
    1030             if (linePtr == end || *linePtr != '@')
    1031             {
    1032                 // parse message name
    1033                 if (getNameArg(asmr, 25, name, linePtr, "message name", true))
    1034                 {
    1035                     toLowerString(name);
    1036                     const size_t msgNameIndex = (::strncmp(name, "msg_", 4) == 0) ? 4 : 0;
    1037                     // choose message name table
    1038                     auto msgMap = isGCN14 ? sendMessageNamesGCN14Map :
    1039                             sendMessageNamesMap;
    1040                     const size_t msgMapSize = isGCN14 ?
    1041                             sendMessageNamesGCN14MapSize : sendMessageNamesMapSize;
    1042                     // find message name
    1043                     size_t index = binaryMapFind(msgMap, msgMap + msgMapSize,
    1044                             name+msgNameIndex, CStringLess()) - msgMap;
    1045                     if (index != msgMapSize &&
    1046                         // save_wave only for GCN1.2
    1047                         (msgMap[index].second!=4 || (arch&ARCH_GCN_1_2_4)!=0))
    1048                         sendMessage = msgMap[index].second;
    1049                     else
    1050                         ASM_NOTGOOD_BY_ERROR(funcArg1Place, "Unknown message")
    1051                 }
    1052                 else
    1053                     good = false;
    1054             }
    1055             else
    1056             {
    1057                 // parametrization
    1058                 linePtr++;
    1059                 good &= parseImm(asmr, linePtr, sendMessage, nullptr, 4, WS_UNSIGNED);
    1060             }
    1061            
    1062             cxuint gsopIndex = 0;
    1063             cxuint streamId = 0;
    1064             if (sendMessage == 2 || sendMessage == 3)
    1065             {
    1066                 if (!skipRequiredComma(asmr, linePtr))
    1067                     return false;
    1068                 skipSpacesToEnd(linePtr, end);
    1069                
    1070                 // parse GSOP parameter
    1071                 if (linePtr == end || *linePtr != '@')
    1072                 {
    1073                     const char* funcArg2Place = linePtr;
    1074                     if (getNameArg(asmr, 20, name, linePtr, "GSOP", true))
    1075                     {
    1076                         toLowerString(name);
    1077                         // handle gs_op prefix
    1078                         const size_t gsopNameIndex = (::strncmp(name, "gs_op_", 6) == 0)
    1079                                     ? 6 : 0;
    1080                         for (gsopIndex = 0; gsopIndex < 4; gsopIndex++)
    1081                             if (::strcmp(name+gsopNameIndex,
    1082                                         sendMsgGSOPTable[gsopIndex])==0)
    1083                                 break;
    1084                         if (gsopIndex==2 && gsopNameIndex==0)
    1085                         {
    1086                             /* 'emit-cut' handling */
    1087                             if (linePtr+4<=end && ::strncasecmp(linePtr, "-cut", 4)==0 &&
    1088                                 (linePtr==end || (!isAlnum(*linePtr) && *linePtr!='_' &&
    1089                                 *linePtr!='$' && *linePtr!='.')))
    1090                             {
    1091                                 linePtr+=4;
    1092                                 gsopIndex++;
    1093                             }
    1094                         }
    1095                         if (gsopIndex == sendMsgGSOPTableSize)
    1096                         {
    1097                             // not found
    1098                             gsopIndex = 0;
    1099                             ASM_NOTGOOD_BY_ERROR(funcArg2Place, "Unknown GSOP")
    1100                         }
    1101                     }
    1102                     else
    1103                         good = false;
    1104                 }
    1105                 else
    1106                 {
    1107                     // parametrization
    1108                     linePtr++;
    1109                     good &= parseImm(asmr, linePtr, gsopIndex, nullptr, 3, WS_UNSIGNED);
    1110                 }
    1111                
    1112                 if (gsopIndex!=0)
    1113                 {
    1114                     if (!skipRequiredComma(asmr, linePtr))
    1115                         return false;
    1116                    
    1117                     uint64_t value;
    1118                     skipSpacesToEnd(linePtr, end);
    1119                     const char* func3ArgPlace = linePtr;
    1120                     // parse STREAMID (third argument of sendmsg)
    1121                     good &= getAbsoluteValueArg(asmr, value, linePtr, true);
    1122                     if (value > 3)
    1123                         asmr.printWarning(func3ArgPlace,
    1124                                   "StreamId (3rd argument) out of range");
    1125                     streamId = value&3;
    1126                 }
    1127             }
    1128             skipSpacesToEnd(linePtr, end);
    1129             if (linePtr==end || *linePtr!=')')
    1130                 ASM_FAIL_BY_ERROR(linePtr, "Unterminated sendmsg function")
    1131             ++linePtr;
    1132             imm16 = sendMessage | (gsopIndex<<4) | (streamId<<8);
    1133             break;
    1134         }
    1135         case GCN_IMM_NONE:
    1136             // if s_endpgm or s_endpgm_saved then add 'end' to code flow entries
    1137             if (gcnInsn.code1 == 1 || gcnInsn.code1 == 27)
    1138                 asmr.sections[asmr.currentSection].addCodeFlowEntry({
    1139                     size_t(asmr.currentOutPos+4), size_t(0), AsmCodeFlowType::END });
    1140             break;
    1141         default:
    1142             good &= parseImm(asmr, linePtr, imm16, &imm16Expr);
    1143     }
    1144     /// if errors
    1145     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1146         return false;
    1147    
    1148     // put data (instruction word)
    1149     uint32_t word;
    1150     SLEV(word, 0xbf800000U | imm16 | (uint32_t(gcnInsn.code1)<<16));
    1151    
    1152     if (imm16Expr!=nullptr)
    1153         imm16Expr->setTarget(AsmExprTarget(((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL) ?
    1154                 GCNTGT_SOPJMP : GCNTGT_SOPKSIMM16, asmr.currentSection, output.size()));
    1155    
    1156     output.insert(output.end(), reinterpret_cast<cxbyte*>(&word),
    1157             reinterpret_cast<cxbyte*>(&word)+4);
    1158     /// prevent freeing expression
    1159     imm16Expr.release();
    1160     return true;
    1161 }
    1162 
    1163 bool GCNAsmUtils::parseSMRDEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    1164                   const char* instrPlace, const char* linePtr, uint16_t arch,
    1165                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    1166                   GCNEncSize gcnEncSize)
    1167 {
    1168     const char* end = asmr.line+asmr.lineSize;
    1169     bool good = true;
    1170     if (gcnEncSize==GCNEncSize::BIT64)
    1171         ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for SMRD encoding")
    1172     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    1173    
    1174     RegRange dstReg(0, 0);
    1175     RegRange sbaseReg(0, 0);
    1176     RegRange soffsetReg(0, 0);
    1177     cxbyte soffsetVal = 0;
    1178     std::unique_ptr<AsmExpression> soffsetExpr;
    1179     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1180     if (mode1 == GCN_SMRD_ONLYDST)
    1181     {
    1182         // parse SDST (SGPR)
    1183         gcnAsm->setCurrentRVU(0);
    1184         good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    1185                        (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SMRD_SDST, true,
    1186                        INSTROP_SYMREGRANGE|INSTROP_WRITE);
    1187     }
    1188     else if (mode1 != GCN_ARG_NONE)
    1189     {
    1190         const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
    1191         // parse SDST (SGPR's (1-16 registers))
    1192         gcnAsm->setCurrentRVU(0);
    1193         good &= parseSRegRange(asmr, linePtr, dstReg, arch, dregsNum,
    1194                    GCNFIELD_SMRD_SDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE);
    1195         if (!skipRequiredComma(asmr, linePtr))
    1196             return false;
    1197        
    1198         // parse SBASE (2 or 4 registers)
    1199         gcnAsm->setCurrentRVU(1);
    1200         good &= parseSRegRange(asmr, linePtr, sbaseReg, arch,
    1201                    (gcnInsn.mode&GCN_SBASE4)?4:2, GCNFIELD_SMRD_SBASE, true,
    1202                    INSTROP_SYMREGRANGE|INSTROP_READ);
    1203         if (!skipRequiredComma(asmr, linePtr))
    1204             return false;
    1205        
    1206         skipSpacesToEnd(linePtr, end);
    1207         if (linePtr==end || *linePtr!='@')
    1208         {
    1209             // parse SOFFSET (SGPR)
    1210             gcnAsm->setCurrentRVU(2);
    1211             good &= parseSRegRange(asmr, linePtr, soffsetReg, arch, 1,
    1212                        GCNFIELD_SMRD_SOFFSET, false, INSTROP_SYMREGRANGE|INSTROP_READ);
    1213         }
    1214         else // '@' prefix (treat next as expression)
    1215             skipCharAndSpacesToEnd(linePtr, end);
    1216        
    1217         if (!soffsetReg)
    1218         {
    1219             // parse immediate
    1220             soffsetReg.start = 255; // indicate an immediate
    1221             good &= parseImm(asmr, linePtr, soffsetVal, &soffsetExpr, 0, WS_UNSIGNED);
    1222         }
    1223     }
    1224     /// if errors
    1225     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1226         return false;
    1227    
    1228     if (soffsetExpr!=nullptr)
    1229         soffsetExpr->setTarget(AsmExprTarget(GCNTGT_SMRDOFFSET, asmr.currentSection,
    1230                        output.size()));
    1231    
    1232     // put data (instruction word)
    1233     uint32_t word;
    1234     SLEV(word, 0xc0000000U | (uint32_t(gcnInsn.code1)<<22) |
    1235             (uint32_t(dstReg.bstart())<<15) |
    1236             ((sbaseReg.bstart()&~1U)<<8) | ((soffsetReg.isVal(255)) ? 0x100 : 0) |
    1237             ((soffsetReg.isVal(255)) ? soffsetVal : soffsetReg.bstart()));
    1238     output.insert(output.end(), reinterpret_cast<cxbyte*>(&word),
    1239             reinterpret_cast<cxbyte*>(&word)+4);
    1240     /// prevent freeing expression
    1241     soffsetExpr.release();
    1242    
    1243     // update SGPR counting and VCC usage (regflags)
    1244     if (dstReg && !dstReg.isRegVar())
    1245     {
    1246         updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    1247         updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    1248     }
    1249     if (!sbaseReg.isRegVar())
    1250         updateRegFlags(gcnRegs.regFlags, sbaseReg.start, arch);
    1251     if (!soffsetReg.isRegVar())
    1252         updateRegFlags(gcnRegs.regFlags, soffsetReg.start, arch);
    1253     return true;
    1254 }
    1255 
    1256 bool GCNAsmUtils::parseSMEMEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    1257                   const char* instrPlace, const char* linePtr, uint16_t arch,
    1258                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    1259                   GCNEncSize gcnEncSize)
    1260 {
    1261     const char* end = asmr.line+asmr.lineSize;
    1262     bool good = true;
    1263     if (gcnEncSize==GCNEncSize::BIT32)
    1264         ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for SMEM encoding")
    1265    
    1266     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    1267     RegRange dataReg(0, 0);
    1268     RegRange sbaseReg(0, 0);
    1269     RegRange soffsetReg(0, 0);
    1270     uint32_t soffsetVal = 0;
    1271     std::unique_ptr<AsmExpression> soffsetExpr;
    1272     std::unique_ptr<AsmExpression> simm7Expr;
    1273     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1274     const bool isGCN14 = (arch & ARCH_RXVEGA) != 0;
    1275    
    1276     const char* soffsetPlace = nullptr;
    1277     AsmSourcePos soffsetPos;
    1278    
    1279     if (mode1 == GCN_SMRD_ONLYDST)
    1280     {
    1281         // parse SDST (SGPR)
    1282         gcnAsm->setCurrentRVU(0);
    1283         good &= parseSRegRange(asmr, linePtr, dataReg, arch,
    1284                        (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_SMRD_SDST, true,
    1285                        INSTROP_SYMREGRANGE|INSTROP_WRITE);
    1286     }
    1287     else if (mode1 != GCN_ARG_NONE)
    1288     {
    1289         const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
    1290         // parse SDST (SGPR's (1-16 registers))
    1291         gcnAsm->setCurrentRVU(0);
    1292         if ((mode1 & GCN_SMEM_SDATA_IMM)==0)
    1293             good &= parseSRegRange(asmr, linePtr, dataReg, arch, dregsNum,
    1294                     GCNFIELD_SMRD_SDST, true, INSTROP_SYMREGRANGE|
    1295                     ((gcnInsn.mode & GCN_MLOAD) != 0 ? INSTROP_WRITE : INSTROP_READ));
    1296         else
    1297             good &= parseImm(asmr, linePtr, dataReg.start, &simm7Expr, 7);
    1298         if (!skipRequiredComma(asmr, linePtr))
    1299             return false;
    1300        
    1301         // parse SBASE (2 or 4 SGPR's)
    1302         gcnAsm->setCurrentRVU(1);
    1303         good &= parseSRegRange(asmr, linePtr, sbaseReg, arch,
    1304                    (gcnInsn.mode&GCN_SBASE4)?4:2, GCNFIELD_SMRD_SBASE, true,
    1305                    INSTROP_SYMREGRANGE|INSTROP_READ);
    1306         if (!skipRequiredComma(asmr, linePtr))
    1307             return false;
    1308        
    1309         skipSpacesToEnd(linePtr, end);
    1310         if (linePtr==end || *linePtr!='@')
    1311         {
    1312             // parse SOFFSET (SGPR)
    1313             gcnAsm->setCurrentRVU(2);
    1314             const char* soffsetPlace = linePtr;
    1315             good &= parseSRegRange(asmr, linePtr, soffsetReg, arch, 1,
    1316                        GCNFIELD_SMRD_SOFFSET, false, INSTROP_SYMREGRANGE|INSTROP_READ);
    1317             if (good && !isGCN14 && (gcnInsn.mode & GCN_MLOAD) == 0 && soffsetReg &&
    1318                     !soffsetReg.isVal(124))
    1319                 // if no M0 register
    1320                 ASM_NOTGOOD_BY_ERROR(soffsetPlace,
    1321                         "Store/Atomic SMEM instructions accepts only M0 register")
    1322         }
    1323         else // '@' prefix (treat next as expression)
    1324             skipCharAndSpacesToEnd(linePtr, end);
    1325        
    1326         if (!soffsetReg)
    1327         {
    1328             // parse immediate
    1329             soffsetReg.start = 255; // indicate an immediate
    1330             skipSpacesToEnd(linePtr, end);
    1331             soffsetPlace = linePtr;
    1332             soffsetPos = asmr.getSourcePos(soffsetPlace);
    1333             good &= parseImm(asmr, linePtr, soffsetVal, &soffsetExpr,
    1334                         isGCN14 ? 21 : 20, isGCN14 ? WS_BOTH : WS_UNSIGNED);
    1335         }
    1336     }
    1337     bool haveGlc = false;
    1338     bool haveNv = false;
    1339     bool haveOffset = false;
    1340     // parse modifiers
    1341     while (linePtr != end)
    1342     {
    1343         skipSpacesToEnd(linePtr, end);
    1344         if (linePtr == end)
    1345             break;
    1346         const char* modPlace = linePtr;
    1347         char name[10];
    1348         if (getNameArgS(asmr, 10, name, linePtr, "modifier"))
    1349         {
    1350             toLowerString(name);
    1351             if (::strcmp(name, "glc")==0)
    1352                 good &= parseModEnable(asmr, linePtr, haveGlc, "glc modifier");
    1353             else if (isGCN14 && ::strcmp(name, "nv")==0)
    1354                 good &= parseModEnable(asmr, linePtr, haveNv, "nv modifier");
    1355             else if (isGCN14 && ::strcmp(name, "offset")==0)
    1356             {
    1357                 // parse offset and it parameter: offset:XXX
    1358                 if (parseModImm(asmr, linePtr, soffsetVal, &soffsetExpr, "offset",
    1359                         21, WS_BOTH))
    1360                 {
    1361                     if (haveOffset)
    1362                         asmr.printWarning(modPlace, "Offset is already defined");
    1363                     haveOffset = true;
    1364                     if (soffsetReg.isVal(255))
    1365                         // illegal second offset
    1366                         ASM_NOTGOOD_BY_ERROR(modPlace, "Illegal second offset");
    1367                 }
    1368                 else
    1369                     good = false;
    1370             }
    1371             else
    1372                 ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown SMEM modifier")
    1373         }
    1374         else
    1375             good = false;
    1376     }
    1377     /// if errors
    1378     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1379         return false;
    1380    
    1381     // set expression target for offsets and immediates
    1382     if (soffsetExpr!=nullptr)
    1383         soffsetExpr->setTarget(AsmExprTarget(isGCN14 ?
    1384                     GCNTGT_SMEMOFFSETVEGA : GCNTGT_SMEMOFFSET,
    1385                     asmr.currentSection, output.size()));
    1386     if (simm7Expr!=nullptr)
    1387         simm7Expr->setTarget(AsmExprTarget(GCNTGT_SMEMIMM, asmr.currentSection,
    1388                        output.size()));
    1389     // TODO: add RVU modification for atomics
    1390     bool dataToRead = false;
    1391     bool dataToWrite = false;
    1392     if (dataReg)
    1393     {
    1394         dataToWrite = ((gcnInsn.mode&GCN_MLOAD) != 0 ||
    1395                 ((gcnInsn.mode&GCN_MATOMIC)!=0 && haveGlc));
    1396         dataToRead = (gcnInsn.mode&GCN_MLOAD)==0 || (gcnInsn.mode&GCN_MATOMIC)!=0;
    1397     }
    1398    
    1399     gcnAsm->instrRVUs[0].rwFlags = (dataToRead ? ASMRVU_READ : 0) |
    1400             (dataToWrite ? ASMRVU_WRITE : 0);
    1401     // check fcmpswap
    1402     if ((gcnInsn.mode & GCN_MHALFWRITE) != 0 && dataToWrite &&
    1403             gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
    1404     {
    1405         // fix access
    1406         AsmRegVarUsage& rvu = gcnAsm->instrRVUs[0];
    1407         uint16_t size = rvu.rend-rvu.rstart;
    1408         rvu.rend = rvu.rstart + (size>>1);
    1409         AsmRegVarUsage& nextRvu = gcnAsm->instrRVUs[3];
    1410         nextRvu = rvu;
    1411         nextRvu.regField = GCNFIELD_SMRD_SDSTH;
    1412         nextRvu.rstart += (size>>1);
    1413         nextRvu.rend = rvu.rstart + size;
    1414         nextRvu.rwFlags = ASMRVU_READ;
    1415         nextRvu.align = 0;
    1416     }
    1417    
    1418     // put data (2 instruction words)
    1419     uint32_t words[2];
    1420     SLEV(words[0], 0xc0000000U | (uint32_t(gcnInsn.code1)<<18) | (dataReg.bstart()<<6) |
    1421             (sbaseReg.bstart()>>1) |
    1422             // enable IMM if soffset is immediate or haveOffset with SGPR
    1423             ((soffsetReg.isVal(255) || haveOffset) ? 0x20000 : 0) |
    1424             (haveGlc ? 0x10000 : 0) | (haveNv ? 0x8000 : 0) | (haveOffset ? 0x4000 : 0));
    1425     SLEV(words[1], (
    1426             // store IMM OFFSET if offset: or IMM offset instead SGPR
    1427             ((soffsetReg.isVal(255) || haveOffset) ? soffsetVal : soffsetReg.bstart())) |
    1428             // store SGPR in SOFFSET if have offset and have SGPR offset
    1429                 ((haveOffset && !soffsetReg.isVal(255)) ? (soffsetReg.bstart()<<25) : 0));
    1430    
    1431     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    1432             reinterpret_cast<cxbyte*>(words+2));
    1433     /// prevent freeing expression
    1434     soffsetExpr.release();
    1435     simm7Expr.release();
    1436    
    1437     // update SGPR counting and VCC usage (regflags)
    1438     if (!dataReg.isRegVar() && dataToWrite)
    1439     {
    1440         updateSGPRsNum(gcnRegs.sgprsNum, dataReg.end-1, arch);
    1441         updateRegFlags(gcnRegs.regFlags, dataReg.start, arch);
    1442     }
    1443     if (!sbaseReg.isRegVar())
    1444         updateRegFlags(gcnRegs.regFlags, sbaseReg.start, arch);
    1445     if (!soffsetReg.isRegVar())
    1446         updateRegFlags(gcnRegs.regFlags, soffsetReg.start, arch);
    1447     return true;
    1448 }
    1449 
    1450 // choose between 64-bit immediate (FP64) and 32-bit immediate
    1451 static Flags correctOpType(uint32_t regsNum, Flags typeMask)
    1452 {
    1453     return (regsNum==2 && (typeMask==INSTROP_FLOAT || typeMask==INSTROP_INT)) ?
    1454         INSTROP_V64BIT : typeMask;
    1455 }
    1456 
    1457 static void encodeVOPWords(uint32_t vop0Word, cxbyte modifiers,
    1458         const VOPExtraModifiers& extraMods, const GCNOperand& src0Op,
    1459         const GCNOperand& src1Op, uint32_t immValue, uint16_t mode1,
    1460         // dstMod - (16bits lower value, 16bit - use dstMod instead std encoding
    1461         uint32_t inDstMod, cxuint& wordsNum, uint32_t* words)
    1462 {
    1463     // VOP2 encoding
    1464     cxuint src0out = src0Op.range.bstart();
    1465     if (extraMods.needSDWA)
    1466         src0out = 0xf9;
    1467     else if (extraMods.needDPP)
    1468         src0out = 0xfa;
    1469     SLEV(words[0], vop0Word | uint32_t(src0out));
    1470     if (extraMods.needSDWA)
    1471     {
    1472         const uint32_t dstMod = (inDstMod & 0x10000) ? (inDstMod&0xff00) :
    1473                     ((uint32_t(extraMods.dstSel)<<8) |
    1474                     (uint32_t(extraMods.dstUnused)<<11) |
    1475                     ((modifiers & VOP3_CLAMP) ? 0x2000 : 0) |
    1476                     (uint32_t(modifiers & 3) << 14));
    1477         // if SDWA encoding
    1478         SLEV(words[wordsNum++], dstMod | (src0Op.range.bstart()&0xff) |
    1479                 (uint32_t(extraMods.src0Sel)<<16) |
    1480                 ((src0Op.vopMods&VOPOP_SEXT) ? (1U<<19) : 0) |
    1481                 ((src0Op.vopMods&VOPOP_NEG) ? (1U<<20) : 0) |
    1482                 ((src0Op.vopMods&VOPOP_ABS) ? (1U<<21) : 0) |
    1483                 (uint32_t(extraMods.src1Sel)<<24) |
    1484                 ((src1Op.vopMods&VOPOP_SEXT) ? (1U<<27) : 0) |
    1485                 ((src1Op.vopMods&VOPOP_NEG) ? (1U<<28) : 0) |
    1486                 ((src1Op.vopMods&VOPOP_ABS) ? (1U<<29) : 0) |
    1487                 (src0Op.range.isNonVGPR() ? (1U<<23) : 0) |
    1488                 (src1Op.range.isNonVGPR() ? (1U<<31) : 0));
    1489     }
    1490     else if (extraMods.needDPP)
    1491         // DPP encoding
    1492         SLEV(words[wordsNum++], (src0Op.range.bstart()&0xff) | (extraMods.dppCtrl<<8) |
    1493                 ((modifiers&VOP3_BOUNDCTRL) ? (1U<<19) : 0) |
    1494                 ((src0Op.vopMods&VOPOP_NEG) ? (1U<<20) : 0) |
    1495                 ((src0Op.vopMods&VOPOP_ABS) ? (1U<<21) : 0) |
    1496                 ((src1Op.vopMods&VOPOP_NEG) ? (1U<<22) : 0) |
    1497                 ((src1Op.vopMods&VOPOP_ABS) ? (1U<<23) : 0) |
    1498                 (uint32_t(extraMods.bankMask)<<24) |
    1499                 (uint32_t(extraMods.rowMask)<<28));
    1500     else if (src0Op.range.isVal(255)) // otherwise we check for immediate/literal value
    1501         SLEV(words[wordsNum++], src0Op.value);
    1502     else if (src1Op.range.isVal(255))
    1503         // literal from SRC1
    1504         SLEV(words[wordsNum++], src1Op.value);
    1505     else if (mode1 == GCN_ARG1_IMM || mode1 == GCN_ARG2_IMM)
    1506         SLEV(words[wordsNum++], immValue);
    1507 }
    1508 
    1509 static void encodeVOP3Words(bool isGCN12, const GCNAsmInstruction& gcnInsn,
    1510         cxbyte modifiers, VOPOpModifiers opMods, bool haveDstCC,
    1511         const RegRange& dstReg, const RegRange& dstCCReg, const RegRange& srcCCReg,
    1512         const GCNOperand& src0Op, const GCNOperand& src1Op,
    1513         cxuint& wordsNum, uint32_t* words)
    1514 {
    1515     // VOP3 encoding
    1516     uint32_t code = (isGCN12) ?
    1517             (uint32_t(gcnInsn.code2)<<16) | ((modifiers&VOP3_CLAMP) ? 0x8000 : 0) :
    1518             (uint32_t(gcnInsn.code2)<<17) | ((modifiers&VOP3_CLAMP) ? 0x800 : 0);
    1519     if (haveDstCC) // if VOP3B
    1520         SLEV(words[0], 0xd0000000U | code |
    1521             (dstReg.bstart()&0xff) | (uint32_t(dstCCReg.bstart())<<8));
    1522     else // if VOP3A
    1523         SLEV(words[0], 0xd0000000U | code | (dstReg.bstart()&0xff) |
    1524             ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
    1525             ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
    1526             ((opMods.opselMod&15) << 11));
    1527     // second dword
    1528     SLEV(words[1], src0Op.range.bstart() | (uint32_t(src1Op.range.bstart())<<9) |
    1529         (uint32_t(srcCCReg.bstart())<<18) | (uint32_t(modifiers & 3) << 27) |
    1530         ((src0Op.vopMods & VOPOP_NEG) ? (1U<<29) : 0) |
    1531         ((src1Op.vopMods & VOPOP_NEG) ? (1U<<30) : 0));
    1532     wordsNum++;
    1533 }
    1534 
    1535 bool GCNAsmUtils::parseVOP2Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    1536                   const char* instrPlace, const char* linePtr, uint16_t arch,
    1537                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    1538                   GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
    1539 {
    1540     const char* end = asmr.line+asmr.lineSize;
    1541     bool good = true;
    1542     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1543     const uint16_t mode2 = (gcnInsn.mode & GCN_MASK2);
    1544     const bool isGCN12 = (arch & ARCH_GCN_1_2_4)!=0;
    1545     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    1546     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    1547    
    1548     RegRange dstReg(0, 0);
    1549     RegRange dstCCReg(0, 0);
    1550     RegRange srcCCReg(0, 0);
    1551     gcnAsm->setCurrentRVU(0);
    1552     if (mode1 == GCN_DS1_SGPR)
    1553         // if SGPRS as destination
    1554         good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    1555                        (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_SDST, true,
    1556                        INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
    1557     else
    1558     {
    1559          // if VGPRS as destination
    1560         bool v_mac = ::strncmp(gcnInsn.mnemonic, "v_mac_", 6)==0;
    1561         good &= parseVRegRange(asmr, linePtr, dstReg, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
    1562                         GCNFIELD_VOP_VDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE|
    1563                               (v_mac?INSTROP_READ:0));
    1564     }
    1565    
    1566     const bool haveDstCC = mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC;
    1567     const bool haveSrcCC = mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC;
    1568     if (haveDstCC) /* VOP3b */
    1569     {
    1570         if (!skipRequiredComma(asmr, linePtr))
    1571             return false;
    1572         // parse SDST (in place VCC) (2 SGPR's)
    1573         gcnAsm->setCurrentRVU(1);
    1574         good &= parseSRegRange(asmr, linePtr, dstCCReg, arch, 2, GCNFIELD_VOP3_SDST1, true,
    1575                                INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
    1576     }
    1577    
    1578     GCNOperand src0Op{}, src1Op{};
    1579     std::unique_ptr<AsmExpression> src0OpExpr, src1OpExpr;
    1580     const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
    1581             (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
    1582    
    1583     const Flags vopOpModFlags = ((haveDstCC && !isGCN12) ?
    1584                     INSTROP_VOP3NEG : INSTROP_VOP3MODS);
    1585     if (!skipRequiredComma(asmr, linePtr))
    1586         return false;
    1587     cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
    1588     // parse SRC0 (can be VGPR, SGPR, scalar source, LDS, literal or constant)
    1589     gcnAsm->setCurrentRVU(2);
    1590     good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
    1591             correctOpType(regsNum, literalConstsFlags) | vopOpModFlags |
    1592             INSTROP_SGPR_UNALIGNED|INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
    1593             INSTROP_READ, GCNFIELD_VOP_SRC0);
    1594    
    1595     uint32_t immValue = 0;
    1596     std::unique_ptr<AsmExpression> immExpr;
    1597     if (mode1 == GCN_ARG1_IMM)
    1598     {
    1599         // for V_MADMK_FXxx instruction
    1600         if (!skipRequiredComma(asmr, linePtr))
    1601             return false;
    1602         good &= parseLiteralImm(asmr, linePtr, immValue, &immExpr, literalConstsFlags);
    1603     }
    1604    
    1605     if (!skipRequiredComma(asmr, linePtr))
    1606         return false;
    1607    
    1608     bool sgprRegInSrc1 = mode1 == GCN_DS1_SGPR || mode1 == GCN_SRC1_SGPR;
    1609     skipSpacesToEnd(linePtr, end);
    1610     regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
    1611     gcnAsm->setCurrentRVU(3);
    1612     // parse SRC1 (can be VGPR, SGPR, scalar source, LDS, literal or constant)
    1613     //  except when SGPR for SRC1 when instructions accepts SGPR in this place
    1614     good &= parseOperand(asmr, linePtr, src1Op, &src1OpExpr, arch, regsNum,
    1615             correctOpType(regsNum, literalConstsFlags) | vopOpModFlags |
    1616             (!sgprRegInSrc1 ? INSTROP_VREGS : 0)|INSTROP_SSOURCE|INSTROP_SREGS|
    1617             INSTROP_SGPR_UNALIGNED |
    1618             (src0Op.range.start==255 ? INSTROP_ONLYINLINECONSTS : 0)|
    1619             INSTROP_READ, (!sgprRegInSrc1) ? GCNFIELD_VOP_VSRC1 : GCNFIELD_VOP_SSRC1);
    1620    
    1621     if (mode1 == GCN_ARG2_IMM)
    1622     {
    1623         // for V_MADAK_Fxx instruction
    1624         if (!skipRequiredComma(asmr, linePtr))
    1625             return false;
    1626         good &= parseLiteralImm(asmr, linePtr, immValue, &immExpr, literalConstsFlags);
    1627     }
    1628     else if (haveSrcCC)
    1629     {
    1630         if (!skipRequiredComma(asmr, linePtr))
    1631             return false;
    1632         gcnAsm->setCurrentRVU(4);
    1633         // parse SSRC (VCC) (2 SGPR's)
    1634         good &= parseSRegRange(asmr, linePtr, srcCCReg, arch, 2, GCNFIELD_VOP3_SSRC, true,
    1635                        INSTROP_SYMREGRANGE|INSTROP_UNALIGNED|INSTROP_READ);
    1636     }
    1637    
    1638     // modifiers
    1639     cxbyte modifiers = 0;
    1640     VOPExtraModifiers extraMods{};
    1641     VOPOpModifiers opMods{};
    1642     good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, 3,
    1643                     (isGCN12) ? &extraMods : nullptr,
    1644                     ((!haveDstCC || isGCN12) ? PARSEVOP_WITHCLAMP : 0)|PARSEVOP_WITHSEXT|
    1645                     ((isGCN14 && !haveDstCC) ? PARSEVOP_WITHOPSEL : 0));
    1646     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1647         return false;
    1648    
    1649     // apply VOP modifiers (abs,neg,sext) to operands from modifiers
    1650     if (src0Op)
    1651         src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
    1652                 ((opMods.negMod&1) ? VOPOP_NEG : 0) |
    1653                 ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
    1654     if (src1Op)
    1655         src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
    1656                 ((opMods.negMod&2) ? VOPOP_NEG : 0) |
    1657                 ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
    1658    
    1659     extraMods.needSDWA |= ((src0Op.vopMods | src1Op.vopMods) & VOPOP_SEXT) != 0;
    1660     // determine whether VOP3 encoding is needed
    1661     bool vop3 = /* src1=sgprs and not (DS1_SGPR|src1_SGPR) */
    1662         //((src1Op.range.start<256) ^ sgprRegInSrc1) ||
    1663         ((!isGCN14 || !extraMods.needSDWA) &&
    1664                 (src1Op.range.isNonVGPR() ^ sgprRegInSrc1)) ||
    1665         (!isGCN12 && (src0Op.vopMods!=0 || src1Op.vopMods!=0)) ||
    1666         (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
    1667             /* exclude OMOD if RXVEGA and SDWA used */
    1668             ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0 ||
    1669         /* srcCC!=VCC or dstCC!=VCC */
    1670         //(haveDstCC && dstCCReg.start!=106) || (haveSrcCC && srcCCReg.start!=106) ||
    1671         (haveDstCC && !dstCCReg.isVal(106)) || (haveSrcCC && !srcCCReg.isVal(106)) ||
    1672         ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
    1673    
    1674     if ((src0Op.range.isVal(255) || src1Op.range.isVal(255)) &&
    1675         (src0Op.range.isSGPR() || src0Op.range.isVal(124) ||
    1676          src1Op.range.isSGPR() || src1Op.range.isVal(124)))
    1677         ASM_FAIL_BY_ERROR(instrPlace, "Literal with SGPR or M0 is illegal")
    1678    
    1679     if (vop3) // modify fields in reg usage
    1680     {
    1681         AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
    1682         if (rvus[0].regField != ASMFIELD_NONE)
    1683             rvus[0].regField = (rvus[0].regField==GCNFIELD_VOP_VDST) ? GCNFIELD_VOP3_VDST :
    1684                             GCNFIELD_VOP3_SDST0;
    1685         if (rvus[2].regField != ASMFIELD_NONE)
    1686             rvus[2].regField = GCNFIELD_VOP3_SRC0;
    1687         if (rvus[3].regField != ASMFIELD_NONE)
    1688             rvus[3].regField = GCNFIELD_VOP3_SRC1;
    1689     }
    1690    
    1691     // count number SGPR operands readed by instruction
    1692     cxuint sgprsReaded = 0;
    1693     if (src0Op.range.isSGPR())
    1694         sgprsReaded++;
    1695     if (src1Op.range.isSGPR() && !regRangeCanEqual(src0Op.range, src1Op.range))
    1696         sgprsReaded++;
    1697     if (haveSrcCC)
    1698         // check for third operand (SSRC)
    1699         if (!regRangeCanEqual(src0Op.range, srcCCReg) &&
    1700             !regRangeCanEqual(src1Op.range, srcCCReg))
    1701             sgprsReaded++;
    1702    
    1703     if (sgprsReaded >= 2)
    1704         /* include VCCs (???) */
    1705         ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
    1706    
    1707     const bool needImm = (src0Op.range.start==255 || src1Op.range.start==255 ||
    1708              mode1 == GCN_ARG1_IMM || mode1 == GCN_ARG2_IMM);
    1709    
    1710     bool sextFlags = ((src0Op.vopMods|src1Op.vopMods) & VOPOP_SEXT);
    1711     if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || sextFlags ||
    1712                 gcnVOPEnc!=GCNVOPEnc::NORMAL))
    1713     {
    1714         /* if VOP_SDWA or VOP_DPP is required */
    1715         if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
    1716                     gcnVOPEnc, src0Op, extraMods, instrPlace))
    1717             return false;
    1718         if (gcnAsm->instrRVUs[2].regField != ASMFIELD_NONE)
    1719             gcnAsm->instrRVUs[2].regField = GCNFIELD_DPPSDWA_SRC0;
    1720        
    1721         if (extraMods.needSDWA && isGCN14)
    1722         {
    1723             // fix for extra type operand from SDWA
    1724             AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
    1725             if (rvus[2].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
    1726                 rvus[2].regField = GCNFIELD_DPPSDWA_SSRC0;
    1727             if (rvus[3].regField != ASMFIELD_NONE && src1Op.range.isNonVGPR())
    1728                 rvus[3].regField = GCNFIELD_VOP_SSRC1;
    1729         }
    1730     }
    1731     else if (isGCN12 && ((src0Op.vopMods|src1Op.vopMods) & ~VOPOP_SEXT)!=0 && !sextFlags)
    1732         // if all pass we check we promote VOP3 if only operand modifiers expect sext()
    1733         vop3 = true;
    1734    
    1735     if (isGCN12 && vop3 && haveDstCC && ((src0Op.vopMods|src1Op.vopMods) & VOPOP_ABS) != 0)
    1736         ASM_FAIL_BY_ERROR(instrPlace, "Abs modifier is illegal for VOP3B encoding")
    1737     if (vop3 && needImm)
    1738         ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
    1739    
    1740     if (!checkGCNVOPEncoding(asmr, instrPlace, gcnVOPEnc, &extraMods))
    1741         return false;
    1742    
    1743     // set target expressions if needed
    1744     if (src0OpExpr!=nullptr)
    1745         src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    1746                       output.size()));
    1747     if (src1OpExpr!=nullptr)
    1748         src1OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    1749                       output.size()));
    1750     if (immExpr!=nullptr)
    1751         immExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    1752                       output.size()));
    1753    
    1754     // put data (instruction words)
    1755     cxuint wordsNum = 1;
    1756     uint32_t words[2];
    1757     if (!vop3)
    1758         // VOP2 encoding
    1759         encodeVOPWords((uint32_t(gcnInsn.code1)<<25) |
    1760                 (uint32_t(src1Op.range.bstart()&0xff)<<9) |
    1761                 (uint32_t(dstReg.bstart()&0xff)<<17),
    1762                 modifiers, extraMods, src0Op, src1Op, immValue, mode1,
    1763                 0, wordsNum, words);
    1764     else
    1765         // VOP3 encoding
    1766         encodeVOP3Words(isGCN12, gcnInsn, modifiers, opMods, haveDstCC,
    1767                 dstReg, dstCCReg, srcCCReg, src0Op, src1Op, wordsNum, words);
    1768    
    1769     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    1770         return false;
    1771    
    1772     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    1773             reinterpret_cast<cxbyte*>(words + wordsNum));
    1774     /// prevent freeing expression
    1775     src0OpExpr.release();
    1776     src1OpExpr.release();
    1777     immExpr.release();
    1778     // update register pool (VGPR and SGPR counting)
    1779     if (!dstReg.isRegVar())
    1780     {
    1781         if (dstReg.start>=256)
    1782             updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
    1783         else // sgprs
    1784         {
    1785             updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    1786             updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    1787         }
    1788     }
    1789     // for SRC operands
    1790     if (src0Op.range && !src0Op.range.isRegVar())
    1791         updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    1792     if (src1Op.range && !src1Op.range.isRegVar())
    1793         updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
    1794     if (dstCCReg && !dstCCReg.isRegVar())
    1795     {
    1796         updateSGPRsNum(gcnRegs.sgprsNum, dstCCReg.end-1, arch);
    1797         updateRegFlags(gcnRegs.regFlags, dstCCReg.start, arch);
    1798     }
    1799     if (srcCCReg && !srcCCReg.isRegVar())
    1800         updateRegFlags(gcnRegs.regFlags, srcCCReg.start, arch);
    1801     return true;
    1802 }
    1803 
    1804 bool GCNAsmUtils::parseVOP1Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    1805                   const char* instrPlace, const char* linePtr, uint16_t arch,
    1806                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    1807                   GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
    1808 {
    1809     bool good = true;
    1810     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1811     const uint16_t mode2 = (gcnInsn.mode & GCN_MASK2);
    1812     const bool isGCN12 = (arch & ARCH_GCN_1_2_4)!=0;
    1813     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    1814    
    1815     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    1816     RegRange dstReg(0, 0);
    1817     GCNOperand src0Op{};
    1818     std::unique_ptr<AsmExpression> src0OpExpr;
    1819     cxbyte modifiers = 0;
    1820     if (mode1 != GCN_VOP_ARG_NONE)
    1821     {
    1822         gcnAsm->setCurrentRVU(0);
    1823         if (mode1 == GCN_DST_SGPR)
    1824             // if SGPRS as destination
    1825             good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    1826                            (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_SDST, true,
    1827                            INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
    1828         else // if VGPRS as destination
    1829             good &= parseVRegRange(asmr, linePtr, dstReg,
    1830                        (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP_VDST, true,
    1831                                   INSTROP_SYMREGRANGE|INSTROP_WRITE);
    1832        
    1833         const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
    1834                 (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
    1835        
    1836         if (!skipRequiredComma(asmr, linePtr))
    1837             return false;
    1838         cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
    1839         gcnAsm->setCurrentRVU(1);
    1840         // parse SRC0 (can be VGPR, SGPR, source scalar, literal or cosntant, LDS
    1841         good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
    1842                     correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
    1843                     INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
    1844                     INSTROP_VOP3MODS|INSTROP_READ, GCNFIELD_VOP_SRC0);
    1845     }
    1846     // modifiers
    1847     VOPExtraModifiers extraMods{};
    1848     VOPOpModifiers opMods{};
    1849     good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods,
    1850                   (mode1!=GCN_VOP_ARG_NONE) ? 2 : 0, (isGCN12)?&extraMods:nullptr,
    1851                   PARSEVOP_WITHCLAMP|PARSEVOP_WITHSEXT|
    1852                   (isGCN14 ? PARSEVOP_WITHOPSEL : 0), (mode1!=GCN_VOP_ARG_NONE) ? 2 : 0);
    1853     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    1854         return false;
    1855    
    1856     if (src0Op)
    1857         src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
    1858                 ((opMods.negMod&1) ? VOPOP_NEG : 0) |
    1859                 ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
    1860    
    1861     extraMods.needSDWA |= ((src0Op.vopMods) & VOPOP_SEXT) != 0;
    1862     // check whether VOP3 encoding is needed
    1863     bool vop3 = ((!isGCN12 && src0Op.vopMods!=0) ||
    1864             (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
    1865             /* exclude OMOD if RXVEGA and SDWA used */
    1866             ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0) ||
    1867             ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
    1868     if (vop3) // modify fields in reg usage
    1869     {
    1870         AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
    1871         if (rvus[0].regField != ASMFIELD_NONE)
    1872             rvus[0].regField = (rvus[0].regField==GCNFIELD_VOP_VDST) ?
    1873                         GCNFIELD_VOP3_VDST : GCNFIELD_VOP3_SDST0;
    1874         if (rvus[1].regField != ASMFIELD_NONE)
    1875             rvus[1].regField = GCNFIELD_VOP3_SRC0;
    1876     }
    1877    
    1878     bool sextFlags = (src0Op.vopMods & VOPOP_SEXT);
    1879     bool needImm = (src0Op && src0Op.range.isVal(255));
    1880     if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || sextFlags ||
    1881                 gcnVOPEnc!=GCNVOPEnc::NORMAL))
    1882     {
    1883         /* if VOP_SDWA or VOP_DPP is required */
    1884         if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
    1885                     gcnVOPEnc, src0Op, extraMods, instrPlace))
    1886             return false;
    1887         if (gcnAsm->instrRVUs[1].regField != ASMFIELD_NONE)
    1888             gcnAsm->instrRVUs[1].regField = GCNFIELD_DPPSDWA_SRC0;
    1889         if (extraMods.needSDWA && isGCN14)
    1890         {
    1891             // fix for extra type operand from SDWA
    1892             AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
    1893             if (rvus[1].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
    1894                 rvus[1].regField = GCNFIELD_DPPSDWA_SSRC0;
    1895         }
    1896     }
    1897     else if (isGCN12 && (src0Op.vopMods & ~VOPOP_SEXT)!=0 && !sextFlags)
    1898         // if all pass we check we promote VOP3 if only operand modifiers expect sext()
    1899         vop3 = true;
    1900    
    1901     if (vop3 && src0Op.range.isVal(255))
    1902         ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
    1903    
    1904     if (!checkGCNVOPEncoding(asmr, instrPlace, gcnVOPEnc, &extraMods))
    1905         return false;
    1906    
    1907     if (src0OpExpr!=nullptr)
    1908         src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    1909                       output.size()));
    1910    
    1911     // put data (instruction word)
    1912     cxuint wordsNum = 1;
    1913     uint32_t words[2];
    1914     if (!vop3)
    1915         // VOP1 encoding
    1916         encodeVOPWords(0x7e000000U | (uint32_t(gcnInsn.code1)<<9) |
    1917                 (uint32_t(dstReg.bstart()&0xff)<<17),
    1918                 modifiers, extraMods, src0Op, GCNOperand{ { 256, 257 } }, 0, mode1,
    1919                 0, wordsNum, words);
    1920     else
    1921         // VOP3 encoding
    1922         encodeVOP3Words(isGCN12, gcnInsn, modifiers, opMods, false,
    1923                 dstReg, RegRange{}, RegRange{}, src0Op, GCNOperand{}, wordsNum, words);
    1924    
    1925     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    1926         return false;
    1927    
    1928     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    1929             reinterpret_cast<cxbyte*>(words + wordsNum));
    1930     /// prevent freeing expression
    1931     src0OpExpr.release();
    1932     // update register pool (VGPR and SGPR counting)
    1933     if (dstReg && !dstReg.isRegVar())
    1934     {
    1935         if (dstReg.start>=256)
    1936             updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
    1937         else // sgprs
    1938         {
    1939             updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    1940             updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    1941         }
    1942     }
    1943     if (src0Op.range && !src0Op.range.isRegVar())
    1944         updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    1945     return true;
    1946 }
    1947 
    1948 bool GCNAsmUtils::parseVOPCEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    1949                   const char* instrPlace, const char* linePtr, uint16_t arch,
    1950                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    1951                   GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
    1952 {
    1953     bool good = true;
    1954     const uint16_t mode2 = (gcnInsn.mode & GCN_MASK2);
    1955     const bool isGCN12 = (arch & ARCH_GCN_1_2_4)!=0;
    1956     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    1957    
    1958     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    1959     RegRange dstReg(0, 0);
    1960     GCNOperand src0Op{};
    1961     std::unique_ptr<AsmExpression> src0OpExpr;
    1962     GCNOperand src1Op{};
    1963     std::unique_ptr<AsmExpression> src1OpExpr;
    1964     cxbyte modifiers = 0;
    1965    
    1966     // parse SDST (2 SGPR's)
    1967     gcnAsm->setCurrentRVU(0);
    1968     good &= parseSRegRange(asmr, linePtr, dstReg, arch, 2, GCNFIELD_VOP3_SDST0, true,
    1969                            INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
    1970     if (!skipRequiredComma(asmr, linePtr))
    1971         return false;
    1972    
    1973     const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
    1974                 (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
    1975     cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
    1976     gcnAsm->setCurrentRVU(1);
    1977     // parse SRC0 (can VGPR, SGPR, scalar source,literal or constant)
    1978     good &= parseOperand(asmr, linePtr, src0Op, &src0OpExpr, arch, regsNum,
    1979                     correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
    1980                     INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
    1981                     INSTROP_VOP3MODS|INSTROP_READ, GCNFIELD_VOP_SRC0);
    1982    
    1983     if (!skipRequiredComma(asmr, linePtr))
    1984         return false;
    1985     regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
    1986     gcnAsm->setCurrentRVU(2);
    1987     // parse SRC1 (can VGPR, SGPR, scalar source,literal or constant)
    1988     good &= parseOperand(asmr, linePtr, src1Op, &src1OpExpr, arch, regsNum,
    1989                 correctOpType(regsNum, literalConstsFlags) | INSTROP_VOP3MODS|
    1990                 INSTROP_SGPR_UNALIGNED|INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|
    1991                 INSTROP_READ| (src0Op.range.isVal(255) ? INSTROP_ONLYINLINECONSTS : 0),
    1992                 GCNFIELD_VOP_VSRC1);
    1993     // modifiers
    1994     VOPExtraModifiers extraMods{};
    1995     VOPOpModifiers opMods{};
    1996     good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, 3,
    1997                 (isGCN12)?&extraMods:nullptr, (isGCN14 ? PARSEVOP_NODSTMODS : 0)|
    1998                 PARSEVOP_WITHCLAMP|PARSEVOP_WITHSEXT|(isGCN14 ? PARSEVOP_WITHOPSEL : 0));
    1999     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2000         return false;
    2001    
    2002     // set VOP operand modifiers to src operands
    2003     if (src0Op)
    2004         src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
    2005                 ((opMods.negMod&1) ? VOPOP_NEG : 0) |
    2006                 ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
    2007     if (src1Op)
    2008         src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
    2009                 ((opMods.negMod&2) ? VOPOP_NEG : 0) |
    2010                 ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
    2011    
    2012     // determine whether SDWA is needed or VOP3 encoding needed
    2013     extraMods.needSDWA |= ((src0Op.vopMods | src1Op.vopMods) & VOPOP_SEXT) != 0;
    2014     bool vop3 = //(dstReg.start!=106) || (src1Op.range.start<256) ||
    2015         ((!isGCN14 || !extraMods.needSDWA) && !dstReg.isVal(106)) ||
    2016         ((!isGCN14 || !extraMods.needSDWA) && src1Op.range.isNonVGPR()) ||
    2017         (!isGCN12 && (src0Op.vopMods!=0 || src1Op.vopMods!=0)) ||
    2018         (modifiers&~(VOP3_BOUNDCTRL|(extraMods.needSDWA?VOP3_CLAMP:0)|
    2019             /* exclude OMOD if RXVEGA and SDWA used */
    2020             ((isGCN14 && extraMods.needSDWA) ? 3 : 0)))!=0 ||
    2021         ((opMods.opselMod & 15) != 0) || (gcnEncSize==GCNEncSize::BIT64);
    2022    
    2023     if ((src0Op.range.isVal(255) || src1Op.range.isVal(255)) &&
    2024         (src0Op.range.isSGPR() || src0Op.range.isVal(124) ||
    2025          src1Op.range.isSGPR() || src1Op.range.isVal(124)))
    2026         ASM_FAIL_BY_ERROR(instrPlace, "Literal with SGPR or M0 is illegal")
    2027     if (src0Op.range.isSGPR() && src1Op.range.isSGPR() &&
    2028         !regRangeCanEqual(src0Op.range, src1Op.range))
    2029         /* include VCCs (???) */
    2030         ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
    2031    
    2032     if (vop3)
    2033     {
    2034         // modify fields in reg usage
    2035         AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
    2036         if (rvus[1].regField != ASMFIELD_NONE)
    2037             rvus[1].regField = GCNFIELD_VOP3_SRC0;
    2038         if (rvus[2].regField != ASMFIELD_NONE)
    2039             rvus[2].regField = GCNFIELD_VOP3_SRC1;
    2040     }
    2041    
    2042     const bool needImm = src0Op.range.start==255 || src1Op.range.start==255;
    2043    
    2044     bool sextFlags = ((src0Op.vopMods|src1Op.vopMods) & VOPOP_SEXT);
    2045     if (isGCN12 && (extraMods.needSDWA || extraMods.needDPP || sextFlags ||
    2046                 gcnVOPEnc!=GCNVOPEnc::NORMAL))
    2047     {
    2048         /* if VOP_SDWA or VOP_DPP is required */
    2049         if (!checkGCNVOPExtraModifers(asmr, arch, needImm, sextFlags, vop3,
    2050                     gcnVOPEnc, src0Op, extraMods, instrPlace))
    2051             return false;
    2052         if (gcnAsm->instrRVUs[1].regField != ASMFIELD_NONE)
    2053             gcnAsm->instrRVUs[1].regField = GCNFIELD_DPPSDWA_SRC0;
    2054        
    2055         if (extraMods.needSDWA && isGCN14)
    2056         {
    2057             // fix for extra type operand from SDWA
    2058             AsmRegVarUsage* rvus = gcnAsm->instrRVUs;
    2059             if (rvus[0].regField != ASMFIELD_NONE)
    2060                 rvus[0].regField = GCNFIELD_SDWAB_SDST;
    2061             if (rvus[1].regField != ASMFIELD_NONE && src0Op.range.isNonVGPR())
    2062                 rvus[1].regField = GCNFIELD_DPPSDWA_SSRC0;
    2063             if (rvus[2].regField != ASMFIELD_NONE && src1Op.range.isNonVGPR())
    2064                 rvus[2].regField = GCNFIELD_VOP_SSRC1;
    2065         }
    2066     }
    2067     else if (isGCN12 && ((src0Op.vopMods|src1Op.vopMods) & ~VOPOP_SEXT)!=0 && !sextFlags)
    2068         // if all pass we check we promote VOP3 if only operand modifiers expect sext()
    2069         vop3 = true;
    2070    
    2071     if (vop3 && (src0Op.range.isVal(255) || src1Op.range.isVal(255)))
    2072         ASM_FAIL_BY_ERROR(instrPlace, "Literal in VOP3 encoding is illegal")
    2073    
    2074     if (!checkGCNVOPEncoding(asmr, instrPlace, gcnVOPEnc, &extraMods))
    2075         return false;
    2076    
    2077     if (isGCN14 && extraMods.needSDWA && ((modifiers & VOP3_CLAMP)!=0 || (modifiers&3)!=0))
    2078         ASM_FAIL_BY_ERROR(instrPlace, "Modifiers CLAMP and OMOD is illegal in SDWAB")
    2079    
    2080     if (src0OpExpr!=nullptr)
    2081         src0OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    2082                       output.size()));
    2083     if (src1OpExpr!=nullptr)
    2084         src1OpExpr->setTarget(AsmExprTarget(GCNTGT_LITIMM, asmr.currentSection,
    2085                       output.size()));
    2086    
    2087     // put data (instruction words)
    2088     cxuint wordsNum = 1;
    2089     uint32_t words[2];
    2090     if (!vop3)
    2091     {
    2092         // VOPC encoding
    2093         const uint32_t dstMods = (isGCN14 ? 0x10000 : 0) |
    2094                 ((isGCN14 && !dstReg.isVal(106)) ? ((dstReg.bstart()|0x80)<<8) : 0);
    2095        
    2096         encodeVOPWords(0x7c000000U | (uint32_t(gcnInsn.code1)<<17) |
    2097                 (uint32_t(src1Op.range.bstart()&0xff)<<9),
    2098                 modifiers, extraMods, src0Op, src1Op, 0, 0,
    2099                 dstMods, wordsNum, words);
    2100     }
    2101     else
    2102         // VOP3 encoding
    2103         encodeVOP3Words(isGCN12, gcnInsn, modifiers, opMods, false,
    2104                 dstReg, RegRange{}, RegRange{}, src0Op, src1Op, wordsNum, words);
    2105    
    2106     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    2107         return false;
    2108     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    2109             reinterpret_cast<cxbyte*>(words + wordsNum));
    2110     /// prevent freeing expression
    2111     src0OpExpr.release();
    2112     src1OpExpr.release();
    2113     // update register pool (VGPR and SGPR counting)
    2114     if (dstReg && !dstReg.isRegVar())
    2115     {
    2116         updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    2117         updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    2118     }
    2119     if (src0Op.range && !src0Op.range.isRegVar())
    2120         updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    2121     if (src1Op.range && !src1Op.range.isRegVar())
    2122         updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
    2123     return true;
    2124 }
    2125 
    2126 bool GCNAsmUtils::parseVOP3Encoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    2127                   const char* instrPlace, const char* linePtr, uint16_t arch,
    2128                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    2129                   GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
    2130 {
    2131     bool good = true;
    2132     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    2133     const uint16_t mode2 = (gcnInsn.mode & GCN_MASK2);
    2134     const bool isGCN12 = (arch & ARCH_GCN_1_2_4)!=0;
    2135     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    2136     const bool vop3p = (gcnInsn.mode & GCN_VOP3_VOP3P) != 0;
    2137     if (gcnVOPEnc!=GCNVOPEnc::NORMAL)
    2138         ASM_FAIL_BY_ERROR(instrPlace, "DPP and SDWA encoding is illegal for VOP3")
    2139    
    2140     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    2141     RegRange dstReg(0, 0);
    2142     RegRange sdstReg(0, 0);
    2143     GCNOperand src0Op{};
    2144     GCNOperand src1Op{};
    2145     GCNOperand src2Op{};
    2146    
    2147     const bool is128Ops = (gcnInsn.mode & 0x7000) == GCN_VOP3_DS2_128;
    2148     bool modHigh = false;
    2149     cxbyte modifiers = 0;
    2150     const Flags vop3Mods = ((gcnInsn.encoding == GCNENC_VOP3B) ?
    2151             INSTROP_VOP3NEG : INSTROP_VOP3MODS | INSTROP_NOSEXT) |
    2152             (vop3p ? INSTROP_VOP3P : 0);
    2153    
    2154     // by default OPSEL_HI is [1,1,1] in vop3p instructions
    2155     VOPOpModifiers opMods{ 0, 0, 0, cxbyte(vop3p ? 7<<4 : 0) };
    2156     cxuint operands = 1;
    2157     if (mode1 != GCN_VOP_ARG_NONE)
    2158     {
    2159         gcnAsm->setCurrentRVU(0);
    2160         // parse DST (
    2161         if ((gcnInsn.mode&GCN_VOP3_DST_SGPR)==0)
    2162             good &= parseVRegRange(asmr, linePtr, dstReg,
    2163                        (is128Ops) ? 4 : ((gcnInsn.mode&GCN_REG_DST_64)?2:1),
    2164                        GCNFIELD_VOP3_VDST, true, INSTROP_SYMREGRANGE|INSTROP_WRITE);
    2165         else // SGPRS as dest
    2166             good &= parseSRegRange(asmr, linePtr, dstReg, arch,
    2167                        (gcnInsn.mode&GCN_REG_DST_64)?2:1, GCNFIELD_VOP3_SDST0, true,
    2168                        INSTROP_SYMREGRANGE|INSTROP_SGPR_UNALIGNED|INSTROP_WRITE);
    2169         if (!skipRequiredComma(asmr, linePtr))
    2170             return false;
    2171        
    2172         if (gcnInsn.encoding == GCNENC_VOP3B &&
    2173             (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC || mode1 == GCN_DST_VCC_VSRC2 ||
    2174              mode1 == GCN_S0EQS12)) /* VOP3b */
    2175         {
    2176             // SDST (VCC) (2 SGPR's)
    2177             gcnAsm->setCurrentRVU(1);
    2178             good &= parseSRegRange(asmr, linePtr, sdstReg, arch, 2, GCNFIELD_VOP3_SDST1,
    2179                        true, INSTROP_SYMREGRANGE|INSTROP_WRITE|INSTROP_SGPR_UNALIGNED);
    2180             if (!skipRequiredComma(asmr, linePtr))
    2181                 return false;
    2182         }
    2183         const Flags literalConstsFlags = (mode2==GCN_FLOATLIT) ? INSTROP_FLOAT :
    2184                 (mode2==GCN_F16LIT) ? INSTROP_F16 : INSTROP_INT;
    2185        
    2186         cxuint regsNum;
    2187         if (mode2 != GCN_VOP3_VINTRP)
    2188         {
    2189             // parse SRC0 (can be VGPR, SGPR, scalar source, constant, LDS)
    2190             gcnAsm->setCurrentRVU(2);
    2191             regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
    2192             good &= parseOperand(asmr, linePtr, src0Op, nullptr, arch, regsNum,
    2193                     correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
    2194                     INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_LDS|
    2195                     vop3Mods|INSTROP_ONLYINLINECONSTS|INSTROP_NOLITERALERROR|INSTROP_READ,
    2196                     GCNFIELD_VOP3_SRC0);
    2197             operands++;
    2198         }
    2199        
    2200         if (mode2 == GCN_VOP3_VINTRP)
    2201         {
    2202             // if VINTRP instruction
    2203             gcnAsm->setCurrentRVU(3);
    2204             if (mode1 != GCN_P0_P10_P20)
    2205             {
    2206                 good &= parseOperand(asmr, linePtr, src1Op, nullptr, arch, 1,
    2207                         INSTROP_VREGS|vop3Mods|INSTROP_READ, GCNFIELD_VOP3_SRC1);
    2208             }
    2209             else /* P0_P10_P20 */
    2210                 good &= parseVINTRP0P10P20(asmr, linePtr, src1Op.range);
    2211            
    2212             if (!skipRequiredComma(asmr, linePtr))
    2213                 return false;
    2214            
    2215             cxbyte attr;
    2216             good &= parseVINTRPAttr(asmr, linePtr, attr);
    2217             attr = ((attr&3)<<6) | ((attr&0xfc)>>2);
    2218             src0Op.range = { attr, uint16_t(attr+1) };
    2219            
    2220             if ((gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2)
    2221             {
    2222                 if (!skipRequiredComma(asmr, linePtr))
    2223                     return false;
    2224                 // parse SRC2 (VGPR, SGPR)
    2225                 gcnAsm->setCurrentRVU(4);
    2226                 good &= parseOperand(asmr, linePtr, src2Op, nullptr, arch,
    2227                     (gcnInsn.mode&GCN_REG_SRC2_64)?2:1, vop3Mods|INSTROP_SGPR_UNALIGNED|
    2228                     INSTROP_VREGS|INSTROP_SREGS|INSTROP_READ, GCNFIELD_VOP3_SRC2);
    2229             }
    2230             // high and vop3
    2231             const char* end = asmr.line+asmr.lineSize;
    2232             bool haveOpsel = false;
    2233             bool haveNeg = false, haveAbs = false;
    2234             // own parse VINTRP modifiers with some VOP3 modifiers
    2235             while (true)
    2236             {
    2237                 bool alreadyModDefined = false;
    2238                 skipSpacesToEnd(linePtr, end);
    2239                 if (linePtr==end)
    2240                     break;
    2241                 char modName[10];
    2242                 const char* modPlace = linePtr;
    2243                 if (!getNameArgS(asmr, 10, modName, linePtr, "VINTRP modifier"))
    2244                     continue;
    2245                 if (::strcmp(modName, "high")==0)
    2246                     good &= parseModEnable(asmr, linePtr, modHigh, "high modifier");
    2247                 else if (::strcmp(modName, "vop3")==0)
    2248                 {
    2249                     bool vop3Mod = false;
    2250                     good &= parseModEnable(asmr, linePtr, vop3Mod, "vop3 modifier");
    2251                     modifiers = (modifiers & ~VOP3_VOP3) | (vop3Mod ? VOP3_VOP3 : 0);
    2252                 }
    2253                 else if (parseSingleOMODCLAMP(asmr, linePtr, modPlace, modName, arch,
    2254                         modifiers, opMods,
    2255                         (gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2 ? 4 : 3, PARSEVOP_WITHCLAMP, haveAbs, haveNeg,
    2256                         alreadyModDefined, good))
    2257                 {   // do nothing
    2258                 }
    2259                 else if (::strcmp(modName, "op_sel")==0)
    2260                 {
    2261                     // op_sel with boolean array
    2262                     uint32_t opselVal = 0;
    2263                     if (linePtr!=end && *linePtr==':')
    2264                     {
    2265                         linePtr++;
    2266                         if (parseImmWithBoolArray(asmr, linePtr, opselVal, 4, WS_UNSIGNED))
    2267                         {
    2268                             opMods.opselMod = opselVal;
    2269                             if (haveOpsel)
    2270                                 asmr.printWarning(modPlace, "Opsel is already defined");
    2271                             haveOpsel = true;
    2272                             opMods.opselMod = opselVal;
    2273                         }
    2274                     }
    2275                     else
    2276                         good = false;
    2277                 }
    2278                 else
    2279                     ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown VINTRP modifier")
    2280             }
    2281             if (modHigh)
    2282             {
    2283                 src0Op.range.start+=0x100;
    2284                 src0Op.range.end+=0x100;
    2285             }
    2286         }
    2287         else if (mode1 != GCN_SRC12_NONE)
    2288         {
    2289             // if encoding have two or three source operands
    2290             if (!skipRequiredComma(asmr, linePtr))
    2291                 return false;
    2292             regsNum = (gcnInsn.mode&GCN_REG_SRC1_64)?2:1;
    2293             // parse SRC1 (can be VGPR, SGPR, source scalar, constant)
    2294             gcnAsm->setCurrentRVU(3);
    2295             good &= parseOperand(asmr, linePtr, src1Op, nullptr, arch, regsNum,
    2296                     correctOpType(regsNum, literalConstsFlags)|INSTROP_VREGS|
    2297                     INSTROP_SGPR_UNALIGNED|INSTROP_SSOURCE|INSTROP_SREGS|vop3Mods|
    2298                     INSTROP_ONLYINLINECONSTS|INSTROP_NOLITERALERROR|INSTROP_READ,
    2299                     GCNFIELD_VOP3_SRC1);
    2300             operands++;
    2301            
    2302             if (mode1 != GCN_SRC2_NONE && mode1 != GCN_DST_VCC)
    2303             {
    2304                 if (!skipRequiredComma(asmr, linePtr))
    2305                     return false;
    2306                 regsNum = (gcnInsn.mode&GCN_REG_SRC2_64)?2:1;
    2307                 // parse SRC2 (can be VGPR, SGPR, source scalar, constant)
    2308                 gcnAsm->setCurrentRVU(4);
    2309                 good &= parseOperand(asmr, linePtr, src2Op, nullptr, arch,
    2310                         is128Ops ? 4 : regsNum,
    2311                         correctOpType(regsNum, literalConstsFlags)|INSTROP_SGPR_UNALIGNED|
    2312                         INSTROP_VREGS|INSTROP_SSOURCE|INSTROP_SREGS|INSTROP_READ|
    2313                         vop3Mods|INSTROP_ONLYINLINECONSTS|INSTROP_NOLITERALERROR,
    2314                         GCNFIELD_VOP3_SRC2);
    2315                 operands++;
    2316             }
    2317         }
    2318     }
    2319     // modifiers
    2320     if (mode2 != GCN_VOP3_VINTRP)
    2321         good &= parseVOPModifiers(asmr, linePtr, arch, modifiers, opMods, operands,
    2322                     nullptr, ((isGCN12 || gcnInsn.encoding!=GCNENC_VOP3B) ?
    2323                             PARSEVOP_WITHCLAMP : 0) |
    2324                     ((isGCN14 && gcnInsn.encoding!=GCNENC_VOP3B) ?
    2325                             PARSEVOP_WITHOPSEL : 0) | (vop3p ? PARSEVOP_VOP3P : 0), 3);
    2326     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2327         return false;
    2328    
    2329     // apply VOP modifiers (abs,neg,sext) to operands from modifiers
    2330     if (src0Op)
    2331         src0Op.vopMods |= ((opMods.absMod&1) ? VOPOP_ABS : 0) |
    2332                 ((opMods.negMod&1) ? VOPOP_NEG : 0) |
    2333                 ((opMods.sextMod&1) ? VOPOP_SEXT : 0);
    2334     if (src1Op)
    2335         src1Op.vopMods |= ((opMods.absMod&2) ? VOPOP_ABS : 0) |
    2336                 ((opMods.negMod&2) ? VOPOP_NEG : 0) |
    2337                 ((opMods.sextMod&2) ? VOPOP_SEXT : 0);
    2338     if (src2Op)
    2339         src2Op.vopMods |= ((opMods.absMod&4) ? VOPOP_ABS : 0) |
    2340                 ((opMods.negMod&4) ? VOPOP_NEG : 0);
    2341    
    2342     if (mode2 != GCN_VOP3_VINTRP)
    2343     {
    2344         // count SGPR operands readed by instruction
    2345         cxuint numSgprToRead = 0;
    2346         //if (src0Op.range.start<108)
    2347         if (src0Op.range.isSGPR())
    2348             numSgprToRead++;
    2349         //if (src1Op && src1Op.range.start<108 &&
    2350         if (src1Op && src1Op.range.isSGPR() &&
    2351                     !regRangeCanEqual(src0Op.range, src1Op.range))
    2352             numSgprToRead++;
    2353         //if (src2Op && src2Op.range.start<108 &&
    2354         if (src2Op && src2Op.range.isSGPR())
    2355         {
    2356             if (!regRangeCanEqual(src0Op.range, src2Op.range) &&
    2357                 !regRangeCanEqual(src1Op.range, src2Op.range))
    2358                 numSgprToRead++;
    2359         }
    2360        
    2361         if (numSgprToRead>=2)
    2362             ASM_FAIL_BY_ERROR(instrPlace, "More than one SGPR to read in instruction")
    2363     }
    2364    
    2365     // put data (instruction words)
    2366     uint32_t words[2];
    2367     cxuint wordsNum = 2;
    2368     if (gcnInsn.encoding == GCNENC_VOP3B)
    2369     {
    2370         // VOP3B encoding
    2371         if (!isGCN12)
    2372             SLEV(words[0], 0xd0000000U | (uint32_t(gcnInsn.code1)<<17) |
    2373                 (dstReg.bstart()&0xff) | (uint32_t(sdstReg.bstart())<<8));
    2374         else
    2375             SLEV(words[0], 0xd0000000U | (uint32_t(gcnInsn.code1)<<16) |
    2376                 (dstReg.bstart()&0xff) | (uint32_t(sdstReg.bstart())<<8) |
    2377                 ((modifiers&VOP3_CLAMP) ? 0x8000 : 0));
    2378     }
    2379     else
    2380     {
    2381         // VOP3A
    2382         if (!isGCN12)
    2383             SLEV(words[0], 0xd0000000U | (uint32_t(gcnInsn.code1)<<17) |
    2384                 (dstReg.bstart()&0xff) | ((modifiers&VOP3_CLAMP) ? 0x800: 0) |
    2385                 ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
    2386                 ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
    2387                 ((src2Op.vopMods & VOPOP_ABS) ? 0x400 : 0));
    2388         else if (mode2 != GCN_VOP3_VINTRP || mode1 == GCN_NEW_OPCODE ||
    2389             (gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2 ||
    2390             (modifiers & VOP3_VOP3)!=0 || (src0Op.range.bstart()&0x100)!=0/* high */ ||
    2391             (modifiers & (VOP3_CLAMP|3)) != 0 || opMods.opselMod != 0 ||
    2392             src1Op.vopMods!=0 || src2Op.vopMods!=0)
    2393             // new VOP3 for GCN 1.2
    2394             SLEV(words[0], 0xd0000000U | (uint32_t(gcnInsn.code1)<<16) |
    2395                 (dstReg.bstart()&0xff) | ((modifiers&VOP3_CLAMP) ? 0x8000: 0) |
    2396                 (vop3p ? (uint32_t(opMods.negMod>>4) << 8) /* VOP3P NEG_HI */ :
    2397                     ((src0Op.vopMods & VOPOP_ABS) ? 0x100 : 0) |
    2398                     ((src1Op.vopMods & VOPOP_ABS) ? 0x200 : 0) |
    2399                     ((src2Op.vopMods & VOPOP_ABS) ? 0x400 : 0)) |
    2400                 (((opMods.opselMod & 64) !=0) ? 0x4000 : 0) |
    2401                 ((opMods.opselMod&15) << 11));
    2402         else // VINTRP
    2403         {
    2404             SLEV(words[0], 0xd4000000U | (src1Op.range.bstart()&0xff) |
    2405                 (uint32_t(src0Op.range.bstart()>>6)<<8) |
    2406                 (uint32_t(src0Op.range.bstart()&63)<<10) |
    2407                 (uint32_t(gcnInsn.code2)<<16) | (uint32_t(dstReg.bstart()&0xff)<<18));
    2408             // VOP3 VINTRP have only one word instruction
    2409             wordsNum--;
    2410         }
    2411     }
    2412     if (wordsNum==2)
    2413         // second instruction's word
    2414         SLEV(words[1], src0Op.range.bstart() | (uint32_t(src1Op.range.bstart())<<9) |
    2415                 (uint32_t(src2Op.range.bstart())<<18) |
    2416                 (vop3p ? ((uint32_t(opMods.opselMod>>4)&3)<<27) :
    2417                  (uint32_t(modifiers & 3) << 27)) |
    2418                 /* in VOP3P is also NEG_LO */
    2419                 ((src0Op.vopMods & VOPOP_NEG) ? (1U<<29) : 0) |
    2420                 ((src1Op.vopMods & VOPOP_NEG) ? (1U<<30) : 0) |
    2421                 ((src2Op.vopMods & VOPOP_NEG) ? (1U<<31) : 0));
    2422    
    2423     if (!checkGCNEncodingSize(asmr, instrPlace, gcnEncSize, wordsNum))
    2424         return false;
    2425     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    2426             reinterpret_cast<cxbyte*>(words + wordsNum));
    2427    
    2428     // update register pool (VGPR and SGPR counting)
    2429     if (dstReg && !dstReg.isRegVar())
    2430     {
    2431         if (dstReg.start>=256)
    2432             updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
    2433         else // sgprs
    2434         {
    2435             updateSGPRsNum(gcnRegs.sgprsNum, dstReg.end-1, arch);
    2436             updateRegFlags(gcnRegs.regFlags, dstReg.start, arch);
    2437         }
    2438     }
    2439     if (sdstReg && !sdstReg.isRegVar())
    2440     {
    2441         updateSGPRsNum(gcnRegs.sgprsNum, sdstReg.end-1, arch);
    2442         updateRegFlags(gcnRegs.regFlags, sdstReg.start, arch);
    2443     }
    2444     if (mode2 != GCN_VOP3_VINTRP)
    2445     {
    2446         // count for SSRC0 and SSRC1 for VOP3A/B encoding (not VINTRP) ???
    2447         if (src0Op.range && !src0Op.range.isRegVar() && src0Op.range.start < 256)
    2448             updateRegFlags(gcnRegs.regFlags, src0Op.range.start, arch);
    2449         if (src1Op.range && !src1Op.range.isRegVar() && src1Op.range.start < 256)
    2450             updateRegFlags(gcnRegs.regFlags, src1Op.range.start, arch);
    2451     }
    2452     if (src2Op.range && !src2Op.range.isRegVar() && src2Op.range.start < 256)
    2453         updateRegFlags(gcnRegs.regFlags, src2Op.range.start, arch);
    2454     return true;
    2455 }
    2456 
    2457 bool GCNAsmUtils::parseVINTRPEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    2458                   const char* instrPlace, const char* linePtr, uint16_t arch,
    2459                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    2460                   GCNEncSize gcnEncSize, GCNVOPEnc gcnVOPEnc)
    2461 {
    2462     bool good = true;
    2463     RegRange dstReg(0, 0);
    2464     RegRange srcReg(0, 0);
    2465     if (gcnEncSize==GCNEncSize::BIT64)
    2466         ASM_FAIL_BY_ERROR(instrPlace, "Only 32-bit size for VINTRP encoding")
    2467     if (gcnVOPEnc!=GCNVOPEnc::NORMAL)
    2468         ASM_FAIL_BY_ERROR(instrPlace, "DPP and SDWA encoding is illegal for VOP3")
    2469    
    2470     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    2471    
    2472     // parse DST (VGPR)
    2473     gcnAsm->setCurrentRVU(0);
    2474     good &= parseVRegRange(asmr, linePtr, dstReg, 1, GCNFIELD_VINTRP_VDST, true,
    2475                         INSTROP_SYMREGRANGE|INSTROP_WRITE);
    2476     if (!skipRequiredComma(asmr, linePtr))
    2477         return false;
    2478    
    2479     if ((gcnInsn.mode & GCN_MASK1) == GCN_P0_P10_P20)
    2480         good &= parseVINTRP0P10P20(asmr, linePtr, srcReg);
    2481     else
    2482     {
    2483         // regular vector register
    2484         gcnAsm->setCurrentRVU(1);
    2485         good &= parseVRegRange(asmr, linePtr, srcReg, 1, GCNFIELD_VINTRP_VSRC0, true,
    2486                         INSTROP_SYMREGRANGE|INSTROP_READ);
    2487     }
    2488    
    2489     if (!skipRequiredComma(asmr, linePtr))
    2490         return false;
    2491    
    2492     cxbyte attrVal;
    2493     good &= parseVINTRPAttr(asmr, linePtr, attrVal);
    2494    
    2495     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2496         return false;
    2497     /* put data (instruction word */
    2498     uint32_t word;
    2499     SLEV(word, 0xc8000000U | (srcReg.bstart()&0xff) | (uint32_t(attrVal&0xff)<<8) |
    2500             (uint32_t(gcnInsn.code1)<<16) | (uint32_t(dstReg.bstart()&0xff)<<18));
    2501     output.insert(output.end(), reinterpret_cast<cxbyte*>(&word),
    2502             reinterpret_cast<cxbyte*>(&word)+4);
    2503     // update register pool (VGPR counting)
    2504     if (!dstReg.isRegVar())
    2505         updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
    2506     return true;
    2507 }
    2508 
    2509 bool GCNAsmUtils::parseDSEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    2510                   const char* instrPlace, const char* linePtr, uint16_t arch,
    2511                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    2512                   GCNEncSize gcnEncSize)
    2513 {
    2514     const char* end = asmr.line+asmr.lineSize;
    2515     bool good = true;
    2516     if (gcnEncSize==GCNEncSize::BIT32)
    2517         ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for DS encoding")
    2518     RegRange dstReg(0, 0);
    2519     RegRange addrReg(0, 0);
    2520     RegRange data0Reg(0, 0), data1Reg(0, 0);
    2521    
    2522     bool beforeData = false;
    2523     bool vdstUsed = false;
    2524    
    2525     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    2526    
    2527     if (((gcnInsn.mode & GCN_ADDR_SRC) != 0 || (gcnInsn.mode & GCN_ONLYDST) != 0) &&
    2528             (gcnInsn.mode & GCN_ONLY_SRC) == 0)
    2529     {
    2530         /* vdst is dst */
    2531         cxuint regsNum = (gcnInsn.mode&GCN_REG_DST_64)?2:1;
    2532         if ((gcnInsn.mode&GCN_DS_96) != 0)
    2533             regsNum = 3;
    2534         if ((gcnInsn.mode&GCN_DS_128) != 0 || (gcnInsn.mode&GCN_DST128) != 0)
    2535             regsNum = 4;
    2536         gcnAsm->setCurrentRVU(0);
    2537         good &= parseVRegRange(asmr, linePtr, dstReg, regsNum, GCNFIELD_DS_VDST, true,
    2538                     INSTROP_SYMREGRANGE|INSTROP_WRITE);
    2539         vdstUsed = beforeData = true;
    2540     }
    2541    
    2542     if ((gcnInsn.mode & GCN_ONLYDST) == 0 && (gcnInsn.mode & GCN_ONLY_SRC) == 0)
    2543     {
    2544         // parse ADDR as first (VGPR)
    2545         if (vdstUsed)
    2546             if (!skipRequiredComma(asmr, linePtr))
    2547                 return false;
    2548         gcnAsm->setCurrentRVU(1);
    2549         good &= parseVRegRange(asmr, linePtr, addrReg, 1, GCNFIELD_DS_ADDR, true,
    2550                     INSTROP_SYMREGRANGE|INSTROP_READ);
    2551         beforeData = true;
    2552     }
    2553    
    2554     const uint16_t srcMode = (gcnInsn.mode & GCN_SRCS_MASK);
    2555    
    2556     if ((gcnInsn.mode & GCN_ONLYDST) == 0 &&
    2557         (gcnInsn.mode & (GCN_ADDR_DST|GCN_ADDR_SRC)) != 0 && srcMode != GCN_NOSRC)
    2558     {
    2559         /* two vdata */
    2560         if (beforeData)
    2561             if (!skipRequiredComma(asmr, linePtr))
    2562                 return false;
    2563        
    2564         cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
    2565         if ((gcnInsn.mode&GCN_DS_96) != 0)
    2566             regsNum = 3;
    2567         if ((gcnInsn.mode&GCN_DS_128) != 0)
    2568             regsNum = 4;
    2569         // parse VDATA0 (VGPR)
    2570         gcnAsm->setCurrentRVU(2);
    2571         good &= parseVRegRange(asmr, linePtr, data0Reg, regsNum, GCNFIELD_DS_DATA0, true,
    2572                     INSTROP_SYMREGRANGE|INSTROP_READ);
    2573         if (srcMode == GCN_2SRCS)
    2574         {
    2575             // insturction have second source
    2576             if (!skipRequiredComma(asmr, linePtr))
    2577                 return false;
    2578             // parse VDATA0 (VGPR)
    2579             gcnAsm->setCurrentRVU(3);
    2580             good &= parseVRegRange(asmr, linePtr, data1Reg,
    2581                        (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, GCNFIELD_DS_DATA1, true,
    2582                                INSTROP_SYMREGRANGE|INSTROP_READ);
    2583         }
    2584     }
    2585    
    2586     bool haveGds = false;
    2587     std::unique_ptr<AsmExpression> offsetExpr, offset2Expr;
    2588     char name[10];
    2589     uint16_t offset = 0;
    2590     cxbyte offset1 = 0, offset2 = 0;
    2591     bool haveOffset = false, haveOffset2 = false;
    2592     // parse DS modifiers
    2593     while (linePtr!=end)
    2594     {
    2595         skipSpacesToEnd(linePtr, end);
    2596         if (linePtr==end)
    2597             break;
    2598         const char* modPlace = linePtr;
    2599         if (!getNameArgS(asmr, 10, name, linePtr, "DS modifier"))
    2600         {
    2601             good = false;
    2602             continue;
    2603         }
    2604         toLowerString(name);
    2605         if (::strcmp(name, "gds")==0)
    2606             good &= parseModEnable(asmr, linePtr, haveGds, "gds modifier");
    2607         else if ((gcnInsn.mode & GCN_2OFFSETS) == 0) /* single offset */
    2608         {
    2609             // single offset
    2610             if (::strcmp(name, "offset") == 0)
    2611             {
    2612                 if (parseModImm(asmr, linePtr, offset, &offsetExpr, "offset",
    2613                             0, WS_UNSIGNED))
    2614                 {
    2615                     // detect multiple occurrences
    2616                     if (haveOffset)
    2617                         asmr.printWarning(modPlace, "Offset is already defined");
    2618                     haveOffset = true;
    2619                 }
    2620                 else
    2621                     good = false;
    2622             }
    2623             else
    2624                 ASM_NOTGOOD_BY_ERROR(modPlace, "Expected 'offset'")
    2625         }
    2626         else
    2627         {
    2628             // two offsets (offset0, offset1)
    2629             if (::memcmp(name, "offset", 6)==0 &&
    2630                 (name[6]=='0' || name[6]=='1') && name[7]==0)
    2631             {
    2632                 skipSpacesToEnd(linePtr, end);
    2633                 if (linePtr!=end && *linePtr==':')
    2634                 {
    2635                     skipCharAndSpacesToEnd(linePtr, end);
    2636                     if (name[6]=='0')
    2637                     {
    2638                         /* offset0 */
    2639                         if (parseImm(asmr, linePtr, offset1, &offsetExpr, 0, WS_UNSIGNED))
    2640                         {
    2641                             // detect multiple occurrences
    2642                             if (haveOffset)
    2643                                 asmr.printWarning(modPlace, "Offset0 is already defined");
    2644                             haveOffset = true;
    2645                         }
    2646                         else
    2647                             good = false;
    2648                     }
    2649                     else
    2650                     {
    2651                         /* offset1 */
    2652                         if (parseImm(asmr, linePtr, offset2, &offset2Expr, 0, WS_UNSIGNED))
    2653                         {
    2654                             // detect multiple occurrences
    2655                             if (haveOffset2)
    2656                                 asmr.printWarning(modPlace, "Offset1 is already defined");
    2657                             haveOffset2 = true;
    2658                         }
    2659                         else
    2660                             good = false;
    2661                     }
    2662                 }
    2663                 else
    2664                     ASM_NOTGOOD_BY_ERROR(linePtr, "Expected ':' before offset")
    2665             }
    2666             else
    2667                 ASM_NOTGOOD_BY_ERROR(modPlace,
    2668                                 "Expected 'offset', 'offset0' or 'offset1'")
    2669         }
    2670     }
    2671    
    2672     if ((gcnInsn.mode & GCN_2OFFSETS) != 0)
    2673         offset = offset1 | (offset2<<8);
    2674    
    2675     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    2676         return false;
    2677    
    2678     if ((gcnInsn.mode&GCN_ONLYGDS) != 0 && !haveGds)
    2679         ASM_FAIL_BY_ERROR(instrPlace, "Instruction requires GDS modifier")
    2680    
    2681     // set target expressions for offsets (if needed)
    2682     if (offsetExpr!=nullptr)
    2683         offsetExpr->setTarget(AsmExprTarget((gcnInsn.mode & GCN_2OFFSETS) ?
    2684                     GCNTGT_DSOFFSET8_0 : GCNTGT_DSOFFSET16, asmr.currentSection,
    2685                     output.size()));
    2686     if (offset2Expr!=nullptr)
    2687         offset2Expr->setTarget(AsmExprTarget(GCNTGT_DSOFFSET8_1, asmr.currentSection,
    2688                     output.size()));
    2689     // put data (two instruction words)
    2690     uint32_t words[2];
    2691     if ((arch & ARCH_GCN_1_2_4)==0)
    2692         SLEV(words[0], 0xd8000000U | uint32_t(offset) | (haveGds ? 0x20000U : 0U) |
    2693                 (uint32_t(gcnInsn.code1)<<18));
    2694     else
    2695         SLEV(words[0], 0xd8000000U | uint32_t(offset) | (haveGds ? 0x10000U : 0U) |
    2696                 (uint32_t(gcnInsn.code1)<<17));
    2697     SLEV(words[1], (addrReg.bstart()&0xff) | (uint32_t(data0Reg.bstart()&0xff)<<8) |
    2698             (uint32_t(data1Reg.bstart()&0xff)<<16) | (uint32_t(dstReg.bstart()&0xff)<<24));
    2699     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    2700             reinterpret_cast<cxbyte*>(words + 2));
    2701    
    2702     offsetExpr.release();
    2703     offset2Expr.release();
    2704     // update register pool (VGPR counting)
    2705     if (dstReg && !dstReg.isRegVar())
    2706         updateVGPRsNum(gcnRegs.vgprsNum, dstReg.end-257);
    2707     return true;
    2708 }
    2709 
    2710 // data format names (sorted by names) (for MUBUF/MTBUF)
    2711 static const std::pair<const char*, uint16_t> mtbufDFMTNamesMap[] =
    2712 {
    2713     { "10_10_10_2", 8 },
    2714     { "10_11_11", 6 },
    2715     { "11_11_10", 7 },
    2716     { "16", 2 },
    2717     { "16_16", 5 },
    2718     { "16_16_16_16", 12 },
    2719     { "2_10_10_10", 9 },
    2720     { "32", 4 },
    2721     { "32_32", 11 },
    2722     { "32_32_32", 13 },
    2723     { "32_32_32_32", 14 },
    2724     { "8", 1 },
    2725     { "8_8", 3 },
    2726     { "8_8_8_8", 10 }
    2727 };
    2728 
    2729 // number format names (sorted by names) (for MUBUF/MTBUF)
    2730 static const std::pair<const char*, cxuint> mtbufNFMTNamesMap[] =
    2731 {
    2732     { "float", 7 },
    2733     { "sint", 5 },
    2734     { "snorm", 1 },
    2735     { "snorm_ogl", 6 },
    2736     { "sscaled", 3 },
    2737     { "uint", 4 },
    2738     { "unorm", 0 },
    2739     { "uscaled", 2 }
    2740 };
    2741 
    2742 bool GCNAsmUtils::parseMUBUFEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    2743                   const char* instrPlace, const char* linePtr, uint16_t arch,
    2744                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    2745                   GCNEncSize gcnEncSize)
    2746 {
    2747     const char* end = asmr.line+asmr.lineSize;
    2748     bool good = true;
    2749     if (gcnEncSize==GCNEncSize::BIT32)
    2750         ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for MUBUF/MTBUF encoding")
    2751     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    2752     RegRange vaddrReg(0, 0);
    2753     RegRange vdataReg(0, 0);
    2754     GCNOperand soffsetOp{};
    2755     RegRange srsrcReg(0, 0);
    2756     const bool isGCN12 = (arch & ARCH_GCN_1_2_4)!=0;
    2757     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    2758     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    2759    
    2760     skipSpacesToEnd(linePtr, end);
    2761     const char* vdataPlace = linePtr;
    2762     const char* vaddrPlace = nullptr;
    2763     bool parsedVaddr = false;
    2764     if (mode1 != GCN_ARG_NONE)
    2765     {
    2766         if (mode1 != GCN_MUBUF_NOVAD)
    2767         {
    2768             gcnAsm->setCurrentRVU(0);
    2769             // parse VDATA (various VGPR number, verified later)
    2770             good &= parseVRegRange(asmr, linePtr, vdataReg, 0, GCNFIELD_M_VDATA, true,
    2771                         INSTROP_SYMREGRANGE|INSTROP_READ);
    2772             if (!skipRequiredComma(asmr, linePtr))
    2773                 return false;
    2774            
    2775             skipSpacesToEnd(linePtr, end);
    2776             vaddrPlace = linePtr;
    2777             gcnAsm->setCurrentRVU(1);
    2778             // parse VADDR (1 or 2 VGPR's) (optional)
    2779             if (!parseVRegRange(asmr, linePtr, vaddrReg, 0, GCNFIELD_M_VADDR, false,
    2780                         INSTROP_SYMREGRANGE|INSTROP_READ))
    2781                 good = false;
    2782             if (vaddrReg) // only if vaddr is
    2783             {
    2784                 parsedVaddr = true;
    2785                 if (!skipRequiredComma(asmr, linePtr))
    2786                     return false;
    2787             }
    2788             else
    2789             {
    2790                 // if not, default is v0, then parse off
    2791                 if (linePtr+3<=end && ::strncasecmp(linePtr, "off", 3)==0 &&
    2792                     (isSpace(linePtr[3]) || linePtr[3]==','))
    2793                 {
    2794                     linePtr+=3;
    2795                     if (!skipRequiredComma(asmr, linePtr))
    2796                         return false;
    2797                 }
    2798                 vaddrReg = {256, 257};
    2799             }
    2800         }
    2801         // parse SRSREG (4 SGPR's)
    2802         gcnAsm->setCurrentRVU(2);
    2803         good &= parseSRegRange(asmr, linePtr, srsrcReg, arch, 4, GCNFIELD_M_SRSRC, true,
    2804                         INSTROP_SYMREGRANGE|INSTROP_READ);
    2805         if (!skipRequiredComma(asmr, linePtr))
    2806             return false;
    2807         // parse SOFFSET (SGPR or scalar source or constant)
    2808         gcnAsm->setCurrentRVU(3);
    2809         good &= parseOperand(asmr, linePtr, soffsetOp, nullptr, arch, 1,
    2810                  INSTROP_SREGS|INSTROP_SSOURCE|INSTROP_ONLYINLINECONSTS|INSTROP_READ|
    2811                  INSTROP_NOLITERALERRORMUBUF, GCNFIELD_M_SOFFSET);
    2812     }
    2813    
    2814     bool haveOffset = false, haveFormat = false;
    2815     cxuint dfmt = 1, nfmt = 0;
    2816     cxuint offset = 0;
    2817     std::unique_ptr<AsmExpression> offsetExpr;
    2818     bool haveAddr64 = false, haveTfe = false, haveSlc = false, haveLds = false;
    2819     bool haveGlc = false, haveOffen = false, haveIdxen = false;
    2820     const char* modName = (gcnInsn.encoding==GCNENC_MTBUF) ?
    2821             "MTBUF modifier" : "MUBUF modifier";
    2822    
    2823     // main loop to parsing MUBUF/MTBUF modifiers
    2824     while(linePtr!=end)
    2825     {
    2826         skipSpacesToEnd(linePtr, end);
    2827         if (linePtr==end)
    2828             break;
    2829         char name[10];
    2830         const char* modPlace = linePtr;
    2831         if (!getNameArgS(asmr, 10, name, linePtr, modName))
    2832         {
    2833             good = false;
    2834             continue;
    2835         }
    2836         toLowerString(name);
    2837        
    2838         if (name[0] == 'o')
    2839         {
    2840             // offen, offset
    2841             if (::strcmp(name+1, "ffen")==0)
    2842                 good &= parseModEnable(asmr, linePtr, haveOffen, "offen modifier");
    2843             else if (::strcmp(name+1, "ffset")==0)
    2844             {
    2845                 // parse offset
    2846                 if (parseModImm(asmr, linePtr, offset, &offsetExpr, "offset",
    2847                                 12, WS_UNSIGNED))
    2848                 {
    2849                     if (haveOffset)
    2850                         asmr.printWarning(modPlace, "Offset is already defined");
    2851                     haveOffset = true;
    2852                 }
    2853                 else
    2854                     good = false;
    2855             }
    2856             else
    2857                 ASM_NOTGOOD_BY_ERROR(modPlace, (gcnInsn.encoding==GCNENC_MUBUF) ?
    2858                     "Unknown MUBUF modifier" : "Unknown MTBUF modifier")
    2859         }
    2860         else if (gcnInsn.encoding==GCNENC_MTBUF && ::strcmp(name, "format")==0)
    2861         {
    2862             // parse format
    2863             bool modGood = true;
    2864             skipSpacesToEnd(linePtr, end);
    2865             if (linePtr==end || *linePtr!=':')
    2866             {
    2867                 ASM_NOTGOOD_BY_ERROR(linePtr, "Expected ':' before format")
    2868                 continue;
    2869             }
    2870             skipCharAndSpacesToEnd(linePtr, end);
    2871            
    2872             // parse [DATA_FORMAT:NUMBER_FORMAT]
    2873             if (linePtr==end || *linePtr!='[')
    2874                 ASM_NOTGOOD_BY_ERROR1(modGood = good, modPlace,
    2875                                 "Expected '[' before format")
    2876             if (modGood)
    2877             {
    2878                 skipCharAndSpacesToEnd(linePtr, end);
    2879                 const char* fmtPlace = linePtr;
    2880                 char fmtName[30];
    2881                 bool haveNFMT = false;
    2882                 if (linePtr != end && *linePtr=='@')
    2883                 {
    2884                     // expression, parse DATA_FORMAT
    2885                     linePtr++;
    2886                     if (!parseImm(asmr, linePtr, dfmt, nullptr, 4, WS_UNSIGNED))
    2887                         modGood = good = false;
    2888                 }
    2889                 else if (getMUBUFFmtNameArg(
    2890                             asmr, 30, fmtName, linePtr, "data/number format"))
    2891                 {
    2892                     toLowerString(fmtName);
    2893                     size_t dfmtNameIndex = (::strncmp(fmtName,
    2894                                  "buf_data_format_", 16)==0) ? 16 : 0;
    2895                     size_t dfmtIdx = binaryMapFind(mtbufDFMTNamesMap, mtbufDFMTNamesMap+14,
    2896                                 fmtName+dfmtNameIndex, CStringLess())-mtbufDFMTNamesMap;
    2897                     if (dfmtIdx != 14)
    2898                         dfmt = mtbufDFMTNamesMap[dfmtIdx].second;
    2899                     else
    2900                     {
    2901                         // nfmt (if not found, then try parse number format)
    2902                         size_t nfmtNameIndex = (::strncmp(fmtName,
    2903                                  "buf_num_format_", 15)==0) ? 15 : 0;
    2904                         size_t nfmtIdx = binaryMapFind(mtbufNFMTNamesMap,
    2905                                mtbufNFMTNamesMap+8, fmtName+nfmtNameIndex,
    2906                                CStringLess())-mtbufNFMTNamesMap;
    2907                         // check if found
    2908                         if (nfmtIdx!=8)
    2909                         {
    2910                             nfmt = mtbufNFMTNamesMap[nfmtIdx].second;
    2911                             haveNFMT = true;
    2912                         }
    2913                         else
    2914                             ASM_NOTGOOD_BY_ERROR1(modGood = good, fmtPlace,
    2915                                         "Unknown data/number format")
    2916                     }
    2917                 }
    2918                 else
    2919                     modGood = good = false;
    2920                
    2921                 skipSpacesToEnd(linePtr, end);
    2922                 if (!haveNFMT && linePtr!=end && *linePtr==',')
    2923                 {
    2924                     skipCharAndSpacesToEnd(linePtr, end);
    2925                     if (linePtr != end && *linePtr=='@')
    2926                     {
    2927                         // expression (number format)
    2928                         linePtr++;
    2929                         if (!parseImm(asmr, linePtr, nfmt, nullptr, 3, WS_UNSIGNED))
    2930                             modGood = good = false;
    2931                     }
    2932                     else
    2933                     {
    2934                         // parse NUMBER format from name
    2935                         fmtPlace = linePtr;
    2936                         good &= getEnumeration(asmr, linePtr, "number format",
    2937                                 8, mtbufNFMTNamesMap, nfmt, "buf_num_format_");
    2938                     }
    2939                 }
    2940                 skipSpacesToEnd(linePtr, end);
    2941                 // close format
    2942                 if (linePtr!=end && *linePtr==']')
    2943                     linePtr++;
    2944                 else
    2945                     ASM_NOTGOOD_BY_ERROR(linePtr, "Unterminated format modifier")
    2946                 if (modGood)
    2947                 {
    2948                     if (haveFormat)
    2949                         asmr.printWarning(modPlace, "Format is already defined");
    2950                     haveFormat = true;
    2951                 }
    2952             }
    2953         }
    2954         // other modifiers
    2955         else if (!isGCN12 && ::strcmp(name, "addr64")==0)
    2956             good &= parseModEnable(asmr, linePtr, haveAddr64, "addr64 modifier");
    2957         else if (::strcmp(name, "tfe")==0)
    2958             good &= parseModEnable(asmr, linePtr, haveTfe, "tfe modifier");
    2959         else if (::strcmp(name, "glc")==0)
    2960             good &= parseModEnable(asmr, linePtr, haveGlc, "glc modifier");
    2961         else if (::strcmp(name, "slc")==0)
    2962             good &= parseModEnable(asmr, linePtr, haveSlc, "slc modifier");
    2963         else if (gcnInsn.encoding==GCNENC_MUBUF && ::strcmp(name, "lds")==0)
    2964             good &= parseModEnable(asmr, linePtr, haveLds, "lds modifier");
    2965         else if (::strcmp(name, "idxen")==0)
    2966             good &= parseModEnable(asmr, linePtr, haveIdxen, "idxen modifier");
    2967         else
    2968             ASM_NOTGOOD_BY_ERROR(modPlace, (gcnInsn.encoding==GCNENC_MUBUF) ?
    2969                     "Unknown MUBUF modifier" : "Unknown MTBUF modifier")
    2970     }
    2971    
    2972     /* checking addr range and vdata range */
    2973     bool vdataToRead = false;
    2974     bool vdataToWrite = false;
    2975     if (vdataReg)
    2976     {
    2977         vdataToWrite = ((gcnInsn.mode&GCN_MLOAD) != 0 ||
    2978                 ((gcnInsn.mode&GCN_MATOMIC)!=0 && haveGlc));
    2979         vdataToRead = (gcnInsn.mode&GCN_MLOAD)==0 ||
    2980                 (gcnInsn.mode&GCN_MATOMIC)!=0;
    2981         // check register range (number of register) in VDATA
    2982         cxuint dregsNum = (((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1);
    2983         if ((gcnInsn.mode & GCN_MUBUF_D16)!=0 && isGCN14)
    2984             // 16-bit values packed into half of number of registers
    2985             dregsNum = (dregsNum+1)>>1;
    2986         dregsNum += (haveTfe);
    2987         if (!isXRegRange(vdataReg, dregsNum))
    2988         {
    2989             char errorMsg[40];
    2990             snprintf(errorMsg, 40, "Required %u vector register%s", dregsNum,
    2991                      (dregsNum>1) ? "s" : "");
    2992             ASM_NOTGOOD_BY_ERROR(vdataPlace, errorMsg)
    2993         }
    2994     }
    2995     if (vaddrReg)
    2996     {
    2997         if (!parsedVaddr && (haveIdxen || haveOffen || haveAddr64))
    2998             // no vaddr in instruction
    2999             ASM_NOTGOOD_BY_ERROR(vaddrPlace, "VADDR is required if idxen, offen "
    3000                     "or addr64 is enabled")
    3001         else
    3002         {
    3003             const cxuint vaddrSize = ((haveOffen&&haveIdxen) || haveAddr64) ? 2 : 1;
    3004             // check register range (number of register) in VADDR
    3005             if (!isXRegRange(vaddrReg, vaddrSize))
    3006                 ASM_NOTGOOD_BY_ERROR(vaddrPlace, (vaddrSize==2) ?
    3007                         "Required 2 vector registers" : "Required 1 vector register")
    3008         }
    3009     }
    3010     // fix access for VDATA field
    3011     gcnAsm->instrRVUs[0].rwFlags = (vdataToWrite ? ASMRVU_WRITE : 0) |
    3012             (vdataToRead ? ASMRVU_READ : 0);
    3013     // check fcmpswap
    3014     bool vdataDivided = false;
    3015     if ((gcnInsn.mode & GCN_MHALFWRITE) != 0 && vdataToWrite && !haveLds &&
    3016         gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
    3017     {
    3018         // fix access
    3019         AsmRegVarUsage& rvu = gcnAsm->instrRVUs[0];
    3020         uint16_t size = rvu.rend-rvu.rstart;
    3021         rvu.rend = rvu.rstart + (size>>1);
    3022         AsmRegVarUsage& nextRvu = gcnAsm->instrRVUs[4];
    3023         nextRvu = rvu;
    3024         nextRvu.regField = GCNFIELD_M_VDATAH;
    3025         nextRvu.rstart += (size>>1);
    3026         nextRvu.rend = rvu.rstart + size;
    3027         nextRvu.rwFlags = ASMRVU_READ;
    3028         vdataDivided = true;
    3029     }
    3030     // do not read vaddr if no offen and idxen and no addr64
    3031     if (!haveAddr64 && !haveOffen && !haveIdxen)
    3032         gcnAsm->instrRVUs[1].regField = ASMFIELD_NONE; // ignore this
    3033    
    3034     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    3035         return false;
    3036    
    3037     /* checking modifiers conditions */
    3038     if (haveAddr64 && (haveOffen || haveIdxen))
    3039         ASM_FAIL_BY_ERROR(instrPlace, "Idxen and offen must be zero in 64-bit address mode")
    3040     if (haveTfe && haveLds)
    3041         ASM_FAIL_BY_ERROR(instrPlace, "Both LDS and TFE is illegal")
    3042    
    3043     // ignore vdata if LDS
    3044     if (haveLds)
    3045         gcnAsm->instrRVUs[0].regField = ASMFIELD_NONE;
    3046    
    3047     if (haveTfe && (vdataDivided ||
    3048             gcnAsm->instrRVUs[0].rwFlags!=(ASMRVU_READ|ASMRVU_WRITE)) &&
    3049             gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
    3050     {
    3051         // fix for tfe
    3052         const cxuint rvuId = (vdataDivided ? 4 : 0);
    3053         AsmRegVarUsage& rvu = gcnAsm->instrRVUs[rvuId];
    3054         AsmRegVarUsage& lastRvu = gcnAsm->instrRVUs[5];
    3055         lastRvu = rvu;
    3056         lastRvu.rstart = lastRvu.rend-1;
    3057         lastRvu.rwFlags = ASMRVU_READ|ASMRVU_WRITE;
    3058         lastRvu.regField = GCNFIELD_M_VDATALAST;
    3059         if (lastRvu.regVar==nullptr) // fix for regusage
    3060         {
    3061             // to save register size for VDATALAST
    3062             lastRvu.rstart = gcnAsm->instrRVUs[0].rstart;
    3063             lastRvu.rend--;
    3064         }
    3065         rvu.rend--;
    3066     }
    3067    
    3068     if (offsetExpr!=nullptr)
    3069         offsetExpr->setTarget(AsmExprTarget(GCNTGT_MXBUFOFFSET, asmr.currentSection,
    3070                     output.size()));
    3071    
    3072     // put data (instruction words)
    3073     uint32_t words[2];
    3074     if (gcnInsn.encoding==GCNENC_MUBUF)
    3075         SLEV(words[0], 0xe0000000U | offset | (haveOffen ? 0x1000U : 0U) |
    3076                 (haveIdxen ? 0x2000U : 0U) | (haveGlc ? 0x4000U : 0U) |
    3077                 ((haveAddr64 && !isGCN12) ? 0x8000U : 0U) | (haveLds ? 0x10000U : 0U) |
    3078                 ((haveSlc && isGCN12) ? 0x20000U : 0) | (uint32_t(gcnInsn.code1)<<18));
    3079     else
    3080     {
    3081         // MTBUF encoding
    3082         uint32_t code = (isGCN12) ? (uint32_t(gcnInsn.code1)<<15) :
    3083                 (uint32_t(gcnInsn.code1)<<16);
    3084         SLEV(words[0], 0xe8000000U | offset | (haveOffen ? 0x1000U : 0U) |
    3085                 (haveIdxen ? 0x2000U : 0U) | (haveGlc ? 0x4000U : 0U) |
    3086                 ((haveAddr64 && !isGCN12) ? 0x8000U : 0U) | code |
    3087                 (uint32_t(dfmt)<<19) | (uint32_t(nfmt)<<23));
    3088     }
    3089     // second word
    3090     SLEV(words[1], (vaddrReg.bstart()&0xff) | (uint32_t(vdataReg.bstart()&0xff)<<8) |
    3091             (uint32_t(srsrcReg.bstart()>>2)<<16) |
    3092             ((haveSlc && (!isGCN12 || gcnInsn.encoding==GCNENC_MTBUF)) ? (1U<<22) : 0) |
    3093             (haveTfe ? (1U<<23) : 0) | (uint32_t(soffsetOp.range.bstart())<<24));
    3094    
    3095     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    3096             reinterpret_cast<cxbyte*>(words + 2));
    3097    
    3098     offsetExpr.release();
    3099     // update register pool (instr loads or save old value) */
    3100     if (vdataReg && !vdataReg.isRegVar() && (vdataToWrite || haveTfe) && !haveLds)
    3101         updateVGPRsNum(gcnRegs.vgprsNum, vdataReg.end-257);
    3102     if (soffsetOp.range && !soffsetOp.range.isRegVar())
    3103         updateRegFlags(gcnRegs.regFlags, soffsetOp.range.start, arch);
    3104     return true;
    3105 }
    3106 
    3107 bool GCNAsmUtils::parseMIMGEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    3108                   const char* instrPlace, const char* linePtr, uint16_t arch,
    3109                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    3110                   GCNEncSize gcnEncSize)
    3111 {
    3112     const char* end = asmr.line+asmr.lineSize;
    3113     if (gcnEncSize==GCNEncSize::BIT32)
    3114         ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for MIMG encoding")
    3115     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    3116     bool good = true;
    3117     RegRange vaddrReg(0, 0);
    3118     RegRange vdataReg(0, 0);
    3119     RegRange ssampReg(0, 0);
    3120     RegRange srsrcReg(0, 0);
    3121     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    3122    
    3123     skipSpacesToEnd(linePtr, end);
    3124     const char* vdataPlace = linePtr;
    3125     gcnAsm->setCurrentRVU(0);
    3126     // parse VDATA (various VGPR number, verified later)
    3127     good &= parseVRegRange(asmr, linePtr, vdataReg, 0, GCNFIELD_M_VDATA, true,
    3128                     INSTROP_SYMREGRANGE|INSTROP_READ);
    3129     if (!skipRequiredComma(asmr, linePtr))
    3130         return false;
    3131    
    3132     skipSpacesToEnd(linePtr, end);
    3133     const char* vaddrPlace = linePtr;
    3134     gcnAsm->setCurrentRVU(1);
    3135     // // parse VADDR (various VGPR number, verified later)
    3136     good &= parseVRegRange(asmr, linePtr, vaddrReg, 0, GCNFIELD_M_VADDR, true,
    3137                     INSTROP_SYMREGRANGE|INSTROP_READ);
    3138     cxuint geRegRequired = (gcnInsn.mode&GCN_MIMG_VA_MASK)+1;
    3139     cxuint vaddrRegsNum = vaddrReg.end-vaddrReg.start;
    3140     cxuint vaddrMaxExtraRegs = (gcnInsn.mode&GCN_MIMG_VADERIV) ? 7 : 3;
    3141     if (vaddrRegsNum < geRegRequired || vaddrRegsNum > geRegRequired+vaddrMaxExtraRegs)
    3142     {
    3143         char buf[60];
    3144         snprintf(buf, 60, "Required (%u-%u) vector registers", geRegRequired,
    3145                  geRegRequired+vaddrMaxExtraRegs);
    3146         ASM_NOTGOOD_BY_ERROR(vaddrPlace, buf)
    3147     }
    3148    
    3149     if (!skipRequiredComma(asmr, linePtr))
    3150         return false;
    3151     skipSpacesToEnd(linePtr, end);
    3152     const char* srsrcPlace = linePtr;
    3153     gcnAsm->setCurrentRVU(2);
    3154     // parse SRSRC (4 or 8 SGPR's) number of register verified later
    3155     good &= parseSRegRange(asmr, linePtr, srsrcReg, arch, 0, GCNFIELD_M_SRSRC, true,
    3156                     INSTROP_SYMREGRANGE|INSTROP_READ);
    3157    
    3158     if ((gcnInsn.mode & GCN_MIMG_SAMPLE) != 0)
    3159     {
    3160         if (!skipRequiredComma(asmr, linePtr))
    3161             return false;
    3162         gcnAsm->setCurrentRVU(3);
    3163         // parse SSAMP (4 SGPR's)
    3164         good &= parseSRegRange(asmr, linePtr, ssampReg, arch, 4, GCNFIELD_MIMG_SSAMP,
    3165                                true, INSTROP_SYMREGRANGE|INSTROP_READ);
    3166     }
    3167    
    3168     bool haveTfe = false, haveSlc = false, haveGlc = false;
    3169     bool haveDa = false, haveR128 = false, haveLwe = false, haveUnorm = false;
    3170     bool haveDMask = false, haveD16 = false, haveA16 = false;
    3171     cxbyte dmask = 0x1;
    3172     /* modifiers and modifiers */
    3173     while(linePtr!=end)
    3174     {
    3175         skipSpacesToEnd(linePtr, end);
    3176         if (linePtr==end)
    3177             break;
    3178         char name[10];
    3179         const char* modPlace = linePtr;
    3180         if (!getNameArgS(asmr, 10, name, linePtr, "MIMG modifier"))
    3181         {
    3182             good = false;
    3183             continue;
    3184         }
    3185         toLowerString(name);
    3186        
    3187         if (name[0] == 'd')
    3188         {
    3189             if (name[1]=='a' && name[2]==0)
    3190                 // DA modifier
    3191                 good &= parseModEnable(asmr, linePtr, haveDa, "da modifier");
    3192             else if ((arch & ARCH_GCN_1_2_4)!=0 && name[1]=='1' &&
    3193                 name[2]=='6' && name[3]==0)
    3194                 // D16 modifier
    3195                 good &= parseModEnable(asmr, linePtr, haveD16, "d16 modifier");
    3196             else if (::strcmp(name+1, "mask")==0)
    3197             {
    3198                 // parse dmask
    3199                 skipSpacesToEnd(linePtr, end);
    3200                 if (linePtr!=end && *linePtr==':')
    3201                 {
    3202                     /* parse dmask immediate */
    3203                     skipCharAndSpacesToEnd(linePtr, end);
    3204                     const char* valuePlace = linePtr;
    3205                     uint64_t value;
    3206                     if (getAbsoluteValueArg(asmr, value, linePtr, true))
    3207                     {
    3208                         // detect multiple occurrences
    3209                         if (haveDMask)
    3210                             asmr.printWarning(modPlace, "Dmask is already defined");
    3211                         haveDMask = true;
    3212                         if (value>0xf)
    3213                             asmr.printWarning(valuePlace, "Dmask out of range (0-15)");
    3214                         dmask = value&0xf;
    3215                         if (dmask == 0)
    3216                             ASM_NOTGOOD_BY_ERROR(valuePlace, "Zero in dmask is illegal")
    3217                     }
    3218                     else
    3219                         good = false;
    3220                 }
    3221                 else
    3222                     ASM_NOTGOOD_BY_ERROR(linePtr, "Expected ':' before dmask")
    3223             }
    3224             else
    3225                 ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown MIMG modifier")
    3226         }
    3227         else if (name[0] < 's')
    3228         {
    3229             // glc, lwe, r128, a16 modifiers
    3230             if (::strcmp(name, "glc")==0)
    3231                 good &= parseModEnable(asmr, linePtr, haveGlc, "glc modifier");
    3232             else if (::strcmp(name, "lwe")==0)
    3233                 good &= parseModEnable(asmr, linePtr, haveLwe, "lwe modifier");
    3234             else if (!isGCN14 && ::strcmp(name, "r128")==0)
    3235                 good &= parseModEnable(asmr, linePtr, haveR128, "r128 modifier");
    3236             else if (isGCN14 && ::strcmp(name, "a16")==0)
    3237                 good &= parseModEnable(asmr, linePtr, haveA16, "a16 modifier");
    3238             else
    3239                 ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown MIMG modifier")
    3240         }
    3241         // other modifiers
    3242         else if (::strcmp(name, "tfe")==0)
    3243             good &= parseModEnable(asmr, linePtr, haveTfe, "tfe modifier");
    3244         else if (::strcmp(name, "slc")==0)
    3245             good &= parseModEnable(asmr, linePtr, haveSlc, "slc modifier");
    3246         else if (::strcmp(name, "unorm")==0)
    3247             good &= parseModEnable(asmr, linePtr, haveUnorm, "unorm modifier");
    3248         else
    3249             ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown MIMG modifier")
    3250     }
    3251    
    3252     cxuint dregsNum = 4;
    3253     // check number of registers in VDATA
    3254     if ((gcnInsn.mode & GCN_MIMG_VDATA4) == 0)
    3255         dregsNum = ((dmask & 1)?1:0) + ((dmask & 2)?1:0) + ((dmask & 4)?1:0) +
    3256                 ((dmask & 8)?1:0) + (haveTfe);
    3257     if (dregsNum!=0 && !isXRegRange(vdataReg, dregsNum))
    3258     {
    3259         char errorMsg[40];
    3260         snprintf(errorMsg, 40, "Required %u vector register%s", dregsNum,
    3261                  (dregsNum>1) ? "s" : "");
    3262         ASM_NOTGOOD_BY_ERROR(vdataPlace, errorMsg)
    3263     }
    3264     // check number of registers in SRSRC
    3265     if (!isXRegRange(srsrcReg, (haveR128)?4:8))
    3266         ASM_NOTGOOD_BY_ERROR(srsrcPlace, (haveR128) ? "Required 4 scalar registers" :
    3267                     "Required 8 scalar registers")
    3268    
    3269     const bool vdataToWrite = ((gcnInsn.mode&GCN_MLOAD) != 0 ||
    3270                 ((gcnInsn.mode&GCN_MATOMIC)!=0 && haveGlc));
    3271     const bool vdataToRead = ((gcnInsn.mode&GCN_MLOAD) == 0 ||
    3272                 ((gcnInsn.mode&GCN_MATOMIC)!=0));
    3273    
    3274     // fix access for VDATA field
    3275     gcnAsm->instrRVUs[0].rwFlags = (vdataToWrite ? ASMRVU_WRITE : 0) |
    3276             (vdataToRead ? ASMRVU_READ : 0);
    3277     // fix alignment
    3278     if (gcnAsm->instrRVUs[2].regVar != nullptr)
    3279         gcnAsm->instrRVUs[2].align = 4;
    3280    
    3281     // check fcmpswap
    3282     bool vdataDivided = false;
    3283     if ((gcnInsn.mode & GCN_MHALFWRITE) != 0 && vdataToWrite &&
    3284         gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
    3285     {
    3286         // fix access
    3287         AsmRegVarUsage& rvu = gcnAsm->instrRVUs[0];
    3288         uint16_t size = rvu.rend-rvu.rstart;
    3289         rvu.rend = rvu.rstart + (size>>1);
    3290         AsmRegVarUsage& nextRvu = gcnAsm->instrRVUs[4];
    3291         nextRvu = rvu;
    3292         nextRvu.regField = GCNFIELD_M_VDATAH;
    3293         nextRvu.rstart += (size>>1);
    3294         nextRvu.rend = rvu.rstart + size;
    3295         nextRvu.rwFlags = ASMRVU_READ;
    3296         vdataDivided = true;
    3297     }
    3298    
    3299     if (haveTfe && (vdataDivided ||
    3300             gcnAsm->instrRVUs[0].rwFlags!=(ASMRVU_READ|ASMRVU_WRITE)) &&
    3301        gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
    3302     {
    3303         // fix for tfe
    3304         const cxuint rvuId = (vdataDivided ? 4 : 0);
    3305         AsmRegVarUsage& rvu = gcnAsm->instrRVUs[rvuId];
    3306         AsmRegVarUsage& lastRvu = gcnAsm->instrRVUs[5];
    3307         lastRvu = rvu;
    3308         lastRvu.rstart = lastRvu.rend-1;
    3309         lastRvu.rwFlags = ASMRVU_READ|ASMRVU_WRITE;
    3310         lastRvu.regField = GCNFIELD_M_VDATALAST;
    3311         if (lastRvu.regVar==nullptr) // fix for regusage
    3312         {
    3313             // to save register size for VDATALAST
    3314             lastRvu.rstart = gcnAsm->instrRVUs[0].rstart;
    3315             lastRvu.rend--;
    3316         }
    3317         rvu.rend--;
    3318     }
    3319    
    3320     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    3321         return false;
    3322    
    3323     /* checking modifiers conditions */
    3324     if (!haveUnorm && ((gcnInsn.mode&GCN_MLOAD) == 0 || (gcnInsn.mode&GCN_MATOMIC)!=0))
    3325         // unorm is not set for this instruction
    3326         ASM_FAIL_BY_ERROR(instrPlace, "Unorm is not set for store or atomic instruction")
    3327    
    3328     // put instruction words
    3329     uint32_t words[2];
    3330     SLEV(words[0], 0xf0000000U | (uint32_t(dmask&0xf)<<8) | (haveUnorm ? 0x1000U : 0) |
    3331         (haveGlc ? 0x2000U : 0) | (haveDa ? 0x4000U : 0) |
    3332         (haveR128|haveA16 ? 0x8000U : 0) |
    3333         (haveTfe ? 0x10000U : 0) | (haveLwe ? 0x20000U : 0) |
    3334         (uint32_t(gcnInsn.code1)<<18) | (haveSlc ? (1U<<25) : 0));
    3335     SLEV(words[1], (vaddrReg.bstart()&0xff) | (uint32_t(vdataReg.bstart()&0xff)<<8) |
    3336             (uint32_t(srsrcReg.bstart()>>2)<<16) | (uint32_t(ssampReg.bstart()>>2)<<21) |
    3337             (haveD16 ? (1U<<31) : 0));
    3338     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    3339             reinterpret_cast<cxbyte*>(words + 2));
    3340    
    3341     // update register pool (instr loads or save old value) */
    3342     if (vdataReg && !vdataReg.isRegVar() && (vdataToWrite || haveTfe))
    3343         updateVGPRsNum(gcnRegs.vgprsNum, vdataReg.end-257);
    3344     return true;
    3345 }
    3346 
    3347 bool GCNAsmUtils::parseEXPEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    3348                   const char* instrPlace, const char* linePtr, uint16_t arch,
    3349                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    3350                   GCNEncSize gcnEncSize)
    3351 {
    3352     const char* end = asmr.line+asmr.lineSize;
    3353     if (gcnEncSize==GCNEncSize::BIT32)
    3354         ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for EXP encoding")
    3355     bool good = true;
    3356     cxbyte enMask = 0xf;
    3357     cxbyte target = 0;
    3358     RegRange vsrcsReg[4];
    3359     const char* vsrcPlaces[4];
    3360     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    3361    
    3362     char name[20];
    3363     skipSpacesToEnd(linePtr, end);
    3364     const char* targetPlace = linePtr;
    3365    
    3366     try
    3367     {
    3368     if (getNameArg(asmr, 20, name, linePtr, "target"))
    3369     {
    3370         size_t nameSize = linePtr-targetPlace;
    3371         const char* nameStart = name;
    3372         toLowerString(name);
    3373         // parse mrt / mrtz / mrt0 - mrt7
    3374         if (name[0]=='m' && name[1]=='r' && name[2]=='t')
    3375         {
    3376             // parse mrtX target
    3377             if (name[3]!='z' || name[4]!=0)
    3378             {
    3379                 nameStart+=3;
    3380                 target = cstrtobyte(nameStart, name+nameSize);
    3381                 if (target>=8)
    3382                     ASM_NOTGOOD_BY_ERROR(targetPlace, "MRT number out of range (0-7)")
    3383             }
    3384             else
    3385                 target = 8; // mrtz
    3386         }
    3387         // parse pos0 - pos3
    3388         else if (name[0]=='p' && name[1]=='o' && name[2]=='s')
    3389         {
    3390             // parse pos target
    3391             nameStart+=3;
    3392             cxbyte posNum = cstrtobyte(nameStart, name+nameSize);
    3393             if (posNum>=4)
    3394                 ASM_NOTGOOD_BY_ERROR(targetPlace, "Pos number out of range (0-3)")
    3395             else
    3396                 target = posNum+12;
    3397         }
    3398         else if (strcmp(name, "null")==0)
    3399             target = 9;
    3400         // param0 - param 31
    3401         else if (memcmp(name, "param", 5)==0)
    3402         {
    3403             nameStart+=5;
    3404             cxbyte posNum = cstrtobyte(nameStart, name+nameSize);
    3405             if (posNum>=32)
    3406                 ASM_NOTGOOD_BY_ERROR(targetPlace, "Param number out of range (0-31)")
    3407             else
    3408                 target = posNum+32;
    3409         }
    3410         else
    3411             ASM_NOTGOOD_BY_ERROR(targetPlace, "Unknown EXP target")
    3412     }
    3413     else
    3414         good = false;
    3415     }
    3416     catch (const ParseException& ex)
    3417     {
    3418         // number parsing error
    3419         asmr.printError(targetPlace, ex.what());
    3420         good = false;
    3421     }
    3422    
    3423     /* parse VSRC0-3 registers */
    3424     for (cxuint i = 0; i < 4; i++)
    3425     {
    3426         if (!skipRequiredComma(asmr, linePtr))
    3427             return false;
    3428         skipSpacesToEnd(linePtr, end);
    3429         vsrcPlaces[i] = linePtr;
    3430         // if not 'off', then parse vector register
    3431         if (linePtr+2>=end || toLower(linePtr[0])!='o' || toLower(linePtr[1])!='f' ||
    3432             toLower(linePtr[2])!='f' || (linePtr+3!=end && isAlnum(linePtr[3])))
    3433         {
    3434             gcnAsm->setCurrentRVU(i);
    3435             good &= parseVRegRange(asmr, linePtr, vsrcsReg[i], 1, GCNFIELD_EXP_VSRC0+i,
    3436                         true, INSTROP_SYMREGRANGE|INSTROP_READ);
    3437         }
    3438         else
    3439         {
    3440             // if vsrcX is off
    3441             enMask &= ~(1U<<i);
    3442             vsrcsReg[i] = { 0, 0 };
    3443             linePtr += 3;
    3444         }
    3445     }
    3446    
    3447     /* EXP modifiers */
    3448     bool haveVM = false, haveCompr = false, haveDone = false;
    3449     while(linePtr!=end)
    3450     {
    3451         skipSpacesToEnd(linePtr, end);
    3452         if (linePtr==end)
    3453             break;
    3454         const char* modPlace = linePtr;
    3455         if (!getNameArgS(asmr, 10, name, linePtr, "EXP modifier"))
    3456         {
    3457             good = false;
    3458             continue;
    3459         }
    3460         toLowerString(name);
    3461         if (name[0]=='v' && name[1]=='m' && name[2]==0)
    3462             good &= parseModEnable(asmr, linePtr, haveVM, "vm modifier");
    3463         else if (::strcmp(name, "done")==0)
    3464             good &= parseModEnable(asmr, linePtr, haveDone, "done modifier");
    3465         else if (::strcmp(name, "compr")==0)
    3466             good &= parseModEnable(asmr, linePtr, haveCompr, "compr modifier");
    3467         else
    3468             ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown EXP modifier")
    3469     }
    3470    
    3471     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    3472         return false;
    3473    
    3474     // checking whether VSRC's is correct in compr mode if enabled
    3475     if (haveCompr && !vsrcsReg[0].isRegVar() && !vsrcsReg[1].isRegVar() &&
    3476             !vsrcsReg[0].isRegVar() && !vsrcsReg[1].isRegVar())
    3477     {
    3478         if (vsrcsReg[0].start!=vsrcsReg[1].start && (enMask&3)==3)
    3479             // error (vsrc1!=vsrc0)
    3480             ASM_FAIL_BY_ERROR(vsrcPlaces[1], "VSRC1 must be equal to VSRC0 in compr mode")
    3481         if (vsrcsReg[2].start!=vsrcsReg[3].start && (enMask&12)==12)
    3482             // error (vsrc3!=vsrc2)
    3483             ASM_FAIL_BY_ERROR(vsrcPlaces[3], "VSRC3 must be equal to VSRC2 in compr mode")
    3484         vsrcsReg[1] = vsrcsReg[2];
    3485         vsrcsReg[2] = vsrcsReg[3] = { 0, 0 };
    3486     }
    3487    
    3488     // put instruction words
    3489     uint32_t words[2];
    3490     SLEV(words[0], ((arch&ARCH_GCN_1_2_4) ? 0xc4000000 : 0xf8000000U) | enMask |
    3491             (uint32_t(target)<<4) | (haveCompr ? 0x400 : 0) | (haveDone ? 0x800 : 0) |
    3492             (haveVM ? 0x1000U : 0));
    3493     SLEV(words[1], uint32_t(vsrcsReg[0].bstart()&0xff) |
    3494             (uint32_t(vsrcsReg[1].bstart()&0xff)<<8) |
    3495             (uint32_t(vsrcsReg[2].bstart()&0xff)<<16) |
    3496             (uint32_t(vsrcsReg[3].bstart()&0xff)<<24));
    3497    
    3498     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    3499             reinterpret_cast<cxbyte*>(words + 2));
    3500     return true;
    3501 }
    3502 
    3503 bool GCNAsmUtils::parseFLATEncoding(Assembler& asmr, const GCNAsmInstruction& gcnInsn,
    3504                   const char* instrPlace, const char* linePtr, uint16_t arch,
    3505                   std::vector<cxbyte>& output, GCNAssembler::Regs& gcnRegs,
    3506                   GCNEncSize gcnEncSize)
    3507 {
    3508     const char* end = asmr.line+asmr.lineSize;
    3509     if (gcnEncSize==GCNEncSize::BIT32)
    3510         ASM_FAIL_BY_ERROR(instrPlace, "Only 64-bit size for FLAT encoding")
    3511     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    3512     const cxuint flatMode = (gcnInsn.mode & GCN_FLAT_MODEMASK);
    3513     bool good = true;
    3514     RegRange vaddrReg(0, 0);
    3515     RegRange vdstReg(0, 0);
    3516     RegRange vdataReg(0, 0);
    3517     RegRange saddrReg(0, 0);
    3518     GCNAssembler* gcnAsm = static_cast<GCNAssembler*>(asmr.isaAssembler);
    3519    
    3520     skipSpacesToEnd(linePtr, end);
    3521     const char* vdstPlace = nullptr;
    3522    
    3523     bool vaddrOff = false;
    3524     const cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
    3525    
    3526     const cxuint addrRegsNum = (flatMode != GCN_FLAT_SCRATCH ?
    3527                 (flatMode==GCN_FLAT_FLAT ? 2 : 0)  : 1);
    3528     const char* addrPlace = nullptr;
    3529     if ((gcnInsn.mode & GCN_FLAT_ADST) == 0)
    3530     {
    3531         // first is destination
    3532         vdstPlace = linePtr;
    3533        
    3534         gcnAsm->setCurrentRVU(0);
    3535         good &= parseVRegRange(asmr, linePtr, vdstReg, 0, GCNFIELD_FLAT_VDST, true,
    3536                         INSTROP_SYMREGRANGE|INSTROP_WRITE);
    3537         if (!skipRequiredComma(asmr, linePtr))
    3538             return false;
    3539         skipSpacesToEnd(linePtr, end);
    3540         addrPlace = linePtr;
    3541         if (flatMode == GCN_FLAT_SCRATCH && linePtr+3<=end &&
    3542             strncasecmp(linePtr, "off", 3)==0 && (linePtr+3==end || !isAlnum(linePtr[3])))
    3543         {
    3544             // // if 'off' word
    3545             vaddrOff = true;
    3546             linePtr+=3;
    3547         }
    3548         else
    3549         {
    3550             gcnAsm->setCurrentRVU(1);
    3551             // parse VADDR (1 or 2 VGPR's)
    3552             good &= parseVRegRange(asmr, linePtr, vaddrReg, addrRegsNum,
    3553                     GCNFIELD_FLAT_ADDR, true, INSTROP_SYMREGRANGE|INSTROP_READ);
    3554         }
    3555     }
    3556     else
    3557     {
    3558         // first is data
    3559         skipSpacesToEnd(linePtr, end);
    3560         addrPlace = linePtr;
    3561         if (flatMode == GCN_FLAT_SCRATCH && linePtr+3<=end &&
    3562             strncasecmp(linePtr, "off", 3)==0 && (linePtr+3==end || !isAlnum(linePtr[3])))
    3563         {
    3564             // if 'off' word
    3565             vaddrOff = true;
    3566             linePtr+=3;
    3567         }
    3568         else
    3569         {
    3570             gcnAsm->setCurrentRVU(1);
    3571             // parse VADDR (1 or 2 VGPR's)
    3572             good &= parseVRegRange(asmr, linePtr, vaddrReg, addrRegsNum,
    3573                         GCNFIELD_FLAT_ADDR, true, INSTROP_SYMREGRANGE|INSTROP_READ);
    3574         }
    3575         if ((gcnInsn.mode & GCN_FLAT_NODST) == 0)
    3576         {
    3577             if (!skipRequiredComma(asmr, linePtr))
    3578                 return false;
    3579             skipSpacesToEnd(linePtr, end);
    3580             vdstPlace = linePtr;
    3581             gcnAsm->setCurrentRVU(0);
    3582             // parse VDST (VGPRs, various number of register, verified later)
    3583             good &= parseVRegRange(asmr, linePtr, vdstReg, 0, GCNFIELD_FLAT_VDST, true,
    3584                         INSTROP_SYMREGRANGE|INSTROP_WRITE);
    3585         }
    3586     }
    3587    
    3588     if ((gcnInsn.mode & GCN_FLAT_NODATA) == 0) /* print data */
    3589     {
    3590         if (!skipRequiredComma(asmr, linePtr))
    3591             return false;
    3592         gcnAsm->setCurrentRVU(2);
    3593         // parse VDATA (VGPRS, 1-4 registers)
    3594         good &= parseVRegRange(asmr, linePtr, vdataReg, dregsNum, GCNFIELD_FLAT_DATA,
    3595                                true, INSTROP_SYMREGRANGE|INSTROP_READ);
    3596     }
    3597    
    3598     bool saddrOff = false;
    3599     if (flatMode != 0)
    3600     {
    3601         // SADDR
    3602         if (!skipRequiredComma(asmr, linePtr))
    3603             return false;
    3604         skipSpacesToEnd(linePtr, end);
    3605         if (flatMode != 0 && linePtr+3<=end && strncasecmp(linePtr, "off", 3)==0 &&
    3606             (linePtr+3==end || !isAlnum(linePtr[3])))
    3607         {  // if 'off' word
    3608             saddrOff = true;
    3609             linePtr+=3;
    3610         }
    3611         else
    3612         {
    3613             gcnAsm->setCurrentRVU(3);
    3614             good &= parseSRegRange(asmr, linePtr, saddrReg, arch,
    3615                         (flatMode==GCN_FLAT_SCRATCH ? 1 : 2), GCNFIELD_FLAT_SADDR, true,
    3616                         INSTROP_SYMREGRANGE|INSTROP_READ);
    3617         }
    3618     }
    3619    
    3620     if (addrRegsNum == 0)
    3621     {
    3622         // check size of addrRange
    3623         // if SADDR then 1 VADDR offset register, otherwise 2 VADDR VGPRs
    3624         cxuint reqAddrRegsNum = saddrOff ? 2 : 1;
    3625         if (!isXRegRange(vaddrReg, reqAddrRegsNum))
    3626         {
    3627             char errorMsg[40];
    3628             snprintf(errorMsg, 40, "Required %u vector register%s", reqAddrRegsNum,
    3629                      (reqAddrRegsNum>1) ? "s" : "");
    3630             ASM_NOTGOOD_BY_ERROR(addrPlace, errorMsg)
    3631         }
    3632     }
    3633    
    3634     if (flatMode == GCN_FLAT_SCRATCH && !saddrOff && !vaddrOff)
    3635         ASM_NOTGOOD_BY_ERROR(instrPlace, "Only one of VADDR and SADDR can be set in "
    3636                     "SCRATCH mode")
    3637    
    3638     if (saddrOff)
    3639         saddrReg.start = 0x7f;
    3640     if (vaddrOff)
    3641         vaddrReg.start = 0x00;
    3642    
    3643     uint16_t instOffset = 0;
    3644     std::unique_ptr<AsmExpression> instOffsetExpr;
    3645     bool haveTfe = false, haveSlc = false, haveGlc = false;
    3646     bool haveNv = false, haveLds = false, haveInstOffset = false;
    3647    
    3648     // main loop to parsing FLAT modifiers
    3649     while(linePtr!=end)
    3650     {
    3651         skipSpacesToEnd(linePtr, end);
    3652         if (linePtr==end)
    3653             break;
    3654         char name[20];
    3655         const char* modPlace = linePtr;
    3656         // get modifier name
    3657         if (!getNameArgS(asmr, 20, name, linePtr, "FLAT modifier"))
    3658         {
    3659             good = false;
    3660             continue;
    3661         }
    3662         // only GCN1.2 modifiers
    3663         if (!isGCN14 && ::strcmp(name, "tfe") == 0)
    3664             good &= parseModEnable(asmr, linePtr, haveTfe, "tfe modifier");
    3665         // only GCN1.4 modifiers
    3666         else if (isGCN14 && ::strcmp(name, "nv") == 0)
    3667             good &= parseModEnable(asmr, linePtr, haveNv, "nv modifier");
    3668         else if (isGCN14 && ::strcmp(name, "lds") == 0)
    3669             good &= parseModEnable(asmr, linePtr, haveLds, "lds modifier");
    3670         // GCN 1.2/1.4 modifiers
    3671         else if (::strcmp(name, "glc") == 0)
    3672             good &= parseModEnable(asmr, linePtr, haveGlc, "glc modifier");
    3673         else if (::strcmp(name, "slc") == 0)
    3674             good &= parseModEnable(asmr, linePtr, haveSlc, "slc modifier");
    3675         else if (isGCN14 && ::strcmp(name, "inst_offset")==0)
    3676         {
    3677             // parse inst_offset, 13-bit with sign, or 12-bit unsigned
    3678             if (parseModImm(asmr, linePtr, instOffset, &instOffsetExpr, "inst_offset",
    3679                             flatMode!=0 ? 13 : 12, flatMode!=0 ? WS_BOTH : WS_UNSIGNED))
    3680             {
    3681                 if (haveInstOffset)
    3682                     asmr.printWarning(modPlace, "InstOffset is already defined");
    3683                 haveInstOffset = true;
    3684             }
    3685             else
    3686                 good = false;
    3687         }
    3688         else
    3689             ASM_NOTGOOD_BY_ERROR(modPlace, "Unknown FLAT modifier")
    3690     }
    3691     /* check register ranges */
    3692     bool dstToWrite = vdstReg && ((gcnInsn.mode & GCN_MATOMIC)==0 || haveGlc);
    3693     if (vdstReg)
    3694     {
    3695         cxuint dstRegsNum = ((gcnInsn.mode & GCN_CMPSWAP)!=0) ? (dregsNum>>1) : dregsNum;
    3696         dstRegsNum = (haveTfe) ? dstRegsNum+1:dstRegsNum; // include tfe
    3697         // check number of registers for VDST
    3698         if (!isXRegRange(vdstReg, dstRegsNum))
    3699         {
    3700             char errorMsg[40];
    3701             snprintf(errorMsg, 40, "Required %u vector register%s", dstRegsNum,
    3702                      (dstRegsNum>1) ? "s" : "");
    3703             ASM_NOTGOOD_BY_ERROR(vdstPlace, errorMsg)
    3704         }
    3705        
    3706         if (haveTfe && vdstReg && gcnAsm->instrRVUs[0].regField != ASMFIELD_NONE)
    3707         {
    3708             // fix for tfe
    3709             AsmRegVarUsage& rvu = gcnAsm->instrRVUs[0];
    3710             AsmRegVarUsage& lastRvu = gcnAsm->instrRVUs[3];
    3711             lastRvu = rvu;
    3712             lastRvu.rstart = lastRvu.rend-1;
    3713             lastRvu.rwFlags = ASMRVU_READ|ASMRVU_WRITE;
    3714             lastRvu.regField = GCNFIELD_FLAT_VDSTLAST;
    3715             if (lastRvu.regVar==nullptr) // fix for regusage
    3716             {
    3717                 // to save register size for VDSTLAST
    3718                 lastRvu.rstart = rvu.rstart;
    3719                 lastRvu.rend--;
    3720             }
    3721             rvu.rend--;
    3722         }
    3723        
    3724         if (!dstToWrite)
    3725             gcnAsm->instrRVUs[0].regField = ASMFIELD_NONE;
    3726     }
    3727    
    3728     if (!good || !checkGarbagesAtEnd(asmr, linePtr))
    3729         return false;
    3730    
    3731     if (instOffsetExpr!=nullptr)
    3732         instOffsetExpr->setTarget(AsmExprTarget(flatMode!=0 ?
    3733                     GCNTGT_INSTOFFSET_S : GCNTGT_INSTOFFSET, asmr.currentSection,
    3734                     output.size()));
    3735    
    3736     // put data (instruction words)
    3737     uint32_t words[2];
    3738     SLEV(words[0], 0xdc000000U | (haveGlc ? 0x10000 : 0) | (haveSlc ? 0x20000: 0) |
    3739             (uint32_t(gcnInsn.code1)<<18) | (haveLds ? 0x2000U : 0) | instOffset |
    3740             (uint32_t(flatMode)<<14));
    3741     SLEV(words[1], (vaddrReg.bstart()&0xff) | (uint32_t(vdataReg.bstart()&0xff)<<8) |
    3742             (haveTfe|haveNv ? (1U<<23) : 0) | (uint32_t(vdstReg.bstart()&0xff)<<24) |
    3743             (uint32_t(saddrReg.bstart())<<16));
    3744    
    3745     output.insert(output.end(), reinterpret_cast<cxbyte*>(words),
    3746             reinterpret_cast<cxbyte*>(words + 2));
    3747    
    3748     instOffsetExpr.release();
    3749     // update register pool
    3750     if (vdstReg && !vdstReg.isRegVar() && (dstToWrite || haveTfe))
    3751         updateVGPRsNum(gcnRegs.vgprsNum, vdstReg.end-257);
    3752     return true;
    3753 }
    3754 
    3755 };
    3756347
    3757348ISAUsageHandler* GCNAssembler::createUsageHandler(std::vector<cxbyte>& content) const
  • CLRadeonExtender/trunk/amdasm/GCNDisasm.cpp

    r3575 r4135  
    2929#include <CLRX/utils/MemAccess.h>
    3030#include "GCNInternals.h"
    31 
    32 namespace CLRX
    33 {
    34 
    35 // type of floating litera
    36 enum FloatLitType: cxbyte
    37 {
    38     FLTLIT_NONE,    // none
    39     FLTLIT_F32,     // single precision
    40     FLTLIT_F16      // half precision
    41 };
    42 
    43 // GCN disassembler code in structure (this allow to access private code of
    44 // GCNDisassembler by these routines
    45 struct CLRX_INTERNAL GCNDisasmUtils
    46 {
    47     typedef GCNDisassembler::RelocIter RelocIter;
    48     static void printLiteral(GCNDisassembler& dasm, size_t codePos, RelocIter& relocIter,
    49               uint32_t literal, FloatLitType floatLit, bool optional);
    50     // decode GCN operand (version without literal)
    51     static void decodeGCNOperandNoLit(GCNDisassembler& dasm, cxuint op, cxuint regNum,
    52               char*& bufPtr, uint16_t arch, FloatLitType floatLit = FLTLIT_NONE);
    53     // decodee GCN operand (include literal, can decode relocations)
    54     static char* decodeGCNOperand(GCNDisassembler& dasm, size_t codePos,
    55               RelocIter& relocIter, cxuint op, cxuint regNum, uint16_t arch,
    56               uint32_t literal = 0, FloatLitType floatLit = FLTLIT_NONE);
    57    
    58     static void decodeSOPCEncoding(GCNDisassembler& dasm,
    59              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    60              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
    61    
    62     static void decodeSOPPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    63              const GCNInstruction& gcnInsn, uint32_t insnCode,
    64              uint32_t literal, size_t pos);
    65    
    66     static void decodeSOP1Encoding(GCNDisassembler& dasm,
    67              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    68              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
    69    
    70     static void decodeSOP2Encoding(GCNDisassembler& dasm,
    71              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    72              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
    73    
    74     static void decodeSOPKEncoding(GCNDisassembler& dasm,
    75              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    76              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal);
    77    
    78     static void decodeSMRDEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    79              const GCNInstruction& gcnInsn, uint32_t insnCode);
    80    
    81     static void decodeSMEMEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    82              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
    83    
    84     static void decodeVOPCEncoding(GCNDisassembler& dasm,
    85              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    86              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
    87              FloatLitType displayFloatLits);
    88    
    89     static void decodeVOP1Encoding(GCNDisassembler& dasm,
    90              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    91              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
    92              FloatLitType displayFloatLits);
    93    
    94     static void decodeVOP2Encoding(GCNDisassembler& dasm,
    95              size_t codePos, RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    96              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
    97              FloatLitType displayFloatLits);
    98    
    99     static void decodeVOP3Encoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    100              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2,
    101              FloatLitType displayFloatLits);
    102    
    103     static void decodeVINTRPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    104              uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode);
    105    
    106     static void decodeDSEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    107              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
    108    
    109     static void decodeMUBUFEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    110             uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    111             uint32_t insnCode2);
    112    
    113     static void decodeMIMGEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    114              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
    115    
    116     static void decodeEXPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    117              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
    118 
    119     static void printFLATAddr(cxuint flatMode, char*& bufPtr, uint32_t insnCode2);
    120    
    121     static void decodeFLATEncoding(GCNDisassembler& dasm, cxuint spacesToAdd, uint16_t arch,
    122              const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t insnCode2);
    123 };
    124 
    125 };
     31#include "GCNDisasmInternals.h"
    12632
    12733using namespace CLRX;
     
    13642    cxuint instrsNum;   // instruction list
    13743};
     44
     45// put chars to buffer (helper)
     46static inline void putChars(char*& buf, const char* input, size_t size)
     47{
     48    ::memcpy(buf, input, size);
     49    buf += size;
     50}
     51
     52// add N spaces (old style), return number
     53static size_t addSpacesOld(char* bufPtr, cxuint spacesToAdd)
     54{
     55    for (cxuint k = spacesToAdd; k>0; k--)
     56        *bufPtr++ = ' ';
     57    return spacesToAdd;
     58}
    13859
    13960// encoding names table
     
    524445};
    525446
    526 // put chars to buffer (helper)
    527 static inline void putChars(char*& buf, const char* input, size_t size)
    528 {
    529     ::memcpy(buf, input, size);
    530     buf += size;
    531 }
    532 
    533 static const char* gcnOperandFloatTable[] =
    534 {
    535     "0.5", "-0.5", "1.0", "-1.0", "2.0", "-2.0", "4.0", "-4.0"
    536 };
    537 
    538 union CLRX_INTERNAL FloatUnion
    539 {
    540     float f;
    541     uint32_t u;
    542 };
    543 
    544 // simple helpers for writing values: bytes, regranges
    545 
    546 static inline void putByteToBuf(cxuint op, char*& bufPtr)
    547 {
    548     cxuint val = op;
    549     if (val >= 100U)
    550     {
    551         cxuint digit2 = val/100U;
    552         *bufPtr++ = digit2+'0';
    553         val -= digit2*100U;
    554     }
    555     {
    556         const cxuint digit1 = val/10U;
    557         if (digit1 != 0 || op >= 100U)
    558             *bufPtr++ = digit1 + '0';
    559         *bufPtr++ = val-digit1*10U + '0';
    560     }
    561 }
    562 
    563 static inline void putHexByteToBuf(cxuint op, char*& bufPtr)
    564 {
    565     const cxuint digit0 = op&0xf;
    566     const cxuint digit1 = (op&0xf0)>>4;
    567     *bufPtr++ = '0';
    568     *bufPtr++ = 'x';
    569     if (digit1 != 0)
    570         *bufPtr++ = (digit1<=9)?'0'+digit1:'a'+digit1-10;
    571     *bufPtr++ = (digit0<=9)?'0'+digit0:'a'+digit0-10;
    572 }
    573 
    574 // print regranges
    575 static void regRanges(cxuint op, cxuint vregNum, char*& bufPtr)
    576 {
    577     if (vregNum!=1)
    578         *bufPtr++ = '[';
    579     putByteToBuf(op, bufPtr);
    580     if (vregNum!=1)
    581     {
    582         *bufPtr++ = ':';
    583         op += vregNum-1;
    584         if (op > 255)
    585             op -= 256; // fix for VREGS
    586         putByteToBuf(op, bufPtr);
    587         *bufPtr++ = ']';
    588     }
    589 }
    590 
    591 static void decodeGCNVRegOperand(cxuint op, cxuint vregNum, char*& bufPtr)
    592 {
    593     *bufPtr++ = 'v';
    594     return regRanges(op, vregNum, bufPtr);
    595 }
    596 
    597 /* parameters: dasm - disassembler, codePos - code position for relocation,
    598  * relocIter, optional - if literal is optional (can be replaced by inline constant) */
    599 void GCNDisasmUtils::printLiteral(GCNDisassembler& dasm, size_t codePos,
    600           RelocIter& relocIter, uint32_t literal, FloatLitType floatLit, bool optional)
    601 {
    602     // if with relocation, just write
    603     if (dasm.writeRelocation(dasm.startOffset + (codePos<<2)-4, relocIter))
    604         return;
    605     FastOutputBuffer& output = dasm.output;
    606     char* bufStart = output.reserve(50);
    607     char* bufPtr = bufStart;
    608     if (optional && (int32_t(literal)<=64 && int32_t(literal)>=-16)) // use lit(...)
    609     {
    610         // use lit() to force correct encoding (avoid constants)
    611         putChars(bufPtr, "lit(", 4);
    612         bufPtr += itocstrCStyle<int32_t>(literal, bufPtr, 11, 10);
    613         *bufPtr++ = ')';
    614     }
    615     else
    616         bufPtr += itocstrCStyle(literal, bufPtr, 11, 16);
    617     if (floatLit != FLTLIT_NONE)
    618     {
    619         // print float point (FP16 or FP32) literal in comment
    620         FloatUnion fu;
    621         fu.u = literal;
    622         putChars(bufPtr, " /* ", 4);
    623         if (floatLit == FLTLIT_F32)
    624             bufPtr += ftocstrCStyle(fu.f, bufPtr, 20);
    625         else
    626             bufPtr += htocstrCStyle(fu.u, bufPtr, 20);
    627         *bufPtr++ = (floatLit == FLTLIT_F32)?'f':'h';
    628         putChars(bufPtr, " */", 3);
    629     }
    630     output.forward(bufPtr-bufStart);
    631 }
    632 
    633 void GCNDisasmUtils::decodeGCNOperandNoLit(GCNDisassembler& dasm, cxuint op,
    634            cxuint regNum, char*& bufPtr, uint16_t arch, FloatLitType floatLit)
    635 {
    636     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    637     const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
    638     const cxuint maxSgprsNum = getGPUMaxRegsNumByArchMask(arch, REGTYPE_SGPR);
    639     if ((op < maxSgprsNum) || (op >= 256 && op < 512))
    640     {
    641         // vector
    642         if (op >= 256)
    643         {
    644             *bufPtr++ = 'v';
    645             op -= 256;
    646         }
    647         // scalar
    648         else
    649             *bufPtr++ = 's';
    650         regRanges(op, regNum, bufPtr);
    651         return;
    652     }
    653    
    654     const cxuint op2 = op&~1U;
    655     if (op2 == 106 || (!isGCN14 && (op2 == 108 || op2 == 110)) || op2 == 126 ||
    656         (op2 == 104 && (arch&ARCH_RX2X0)!=0) ||
    657         ((op2 == 102 || op2 == 104) && isGCN12))
    658     {
    659         // if not SGPR, but other scalar registers
    660         switch(op2)
    661         {
    662             case 102:
    663                 putChars(bufPtr, "flat_scratch", 12);
    664                 break;
    665             case 104:
    666                 if (isGCN12) // GCN1.2
    667                     putChars(bufPtr, "xnack_mask", 10);
    668                 else // GCN1.1
    669                     putChars(bufPtr, "flat_scratch", 12);
    670                 break;
    671             case 106:
    672                 // vcc
    673                 *bufPtr++ = 'v';
    674                 *bufPtr++ = 'c';
    675                 *bufPtr++ = 'c';
    676                 break;
    677             case 108:
    678                 // tba
    679                 *bufPtr++ = 't';
    680                 *bufPtr++ = 'b';
    681                 *bufPtr++ = 'a';
    682                 break;
    683             case 110:
    684                 // tma
    685                 *bufPtr++ = 't';
    686                 *bufPtr++ = 'm';
    687                 *bufPtr++ = 'a';
    688                 break;
    689             case 126:
    690                 putChars(bufPtr, "exec", 4);
    691                 break;
    692         }
    693         // if full 64-bit register
    694         if (regNum >= 2)
    695         {
    696             if (op&1) // unaligned!!
    697             {
    698                 *bufPtr++ = '_';
    699                 *bufPtr++ = 'u';
    700                 *bufPtr++ = '!';
    701             }
    702             if (regNum > 2)
    703                 putChars(bufPtr, "&ill!", 5);
    704             return;
    705         }
    706         // suffix _lo or _hi (like vcc_lo or vcc_hi)
    707         *bufPtr++ = '_';
    708         if ((op&1) == 0)
    709         { *bufPtr++ = 'l'; *bufPtr++ = 'o'; }
    710         else
    711         { *bufPtr++ = 'h'; *bufPtr++ = 'i'; }
    712         return;
    713     }
    714    
    715     if (op == 255) // if literal
    716     {
    717         *bufPtr++ = '0'; // zero
    718         *bufPtr++ = 'x'; // zero
    719         *bufPtr++ = '0'; // zero
    720         return;
    721     }
    722    
    723     cxuint ttmpStart = (isGCN14 ? 108 : 112);
    724     if (op >= ttmpStart && op < 124)
    725     {
    726         // print ttmp register
    727         putChars(bufPtr, "ttmp", 4);
    728         regRanges(op-ttmpStart, regNum, bufPtr);
    729         return;
    730     }
    731     if (op == 124)
    732     {
    733         // M0 register
    734         *bufPtr++ = 'm';
    735         *bufPtr++ = '0';
    736         if (regNum > 1)
    737             putChars(bufPtr, "&ill!", 5);
    738         return;
    739     }
    740    
    741     if (op >= 128 && op <= 192)
    742     {
    743         // nonnegative integer constant
    744         op -= 128;
    745         const cxuint digit1 = op/10U;
    746         if (digit1 != 0)
    747             *bufPtr++ = digit1 + '0';
    748         *bufPtr++ = op-digit1*10U + '0';
    749         return;
    750     }
    751     if (op > 192 && op <= 208)
    752     {
    753         // negative integer constant
    754         *bufPtr++ = '-';
    755         if (op >= 202)
    756         {
    757             *bufPtr++ = '1';
    758             *bufPtr++ = op-202+'0';
    759         }
    760         else
    761             *bufPtr++ = op-192+'0';
    762         return;
    763     }
    764    
    765     Flags disasmFlags = dasm.disassembler.getFlags();
    766     if (op >= 240 && op < 248)
    767     {
    768         const char* inOp = gcnOperandFloatTable[op-240];
    769         putChars(bufPtr, inOp, ::strlen(inOp));
    770         if ((disasmFlags & DISASM_BUGGYFPLIT)!=0 && floatLit==FLTLIT_F16)
    771             *bufPtr++ = 's';    /* old rules of assembler */
    772         return;
    773     }
    774    
    775     if (isGCN14)
    776         // special registers in GCN1.4 (VEGA)
    777         switch(op)
    778         {
    779             case 0xeb:
    780                 putChars(bufPtr, "shared_base", 11);
    781                 return;
    782             case 0xec:
    783                 putChars(bufPtr, "shared_limit", 12);
    784                 return;
    785             case 0xed:
    786                 putChars(bufPtr, "private_base", 12);
    787                 return;
    788             case 0xee:
    789                 putChars(bufPtr, "private_limit", 13);
    790                 return;
    791             case 0xef:
    792                 putChars(bufPtr, "pops_exiting_wave_id", 20);
    793                 return;
    794         }
    795    
    796     switch(op)
    797     {
    798         case 248:
    799             if (isGCN12)
    800             {
    801                 // 1/(2*PI)
    802                 putChars(bufPtr, "0.15915494", 10);
    803                 if ((disasmFlags & DISASM_BUGGYFPLIT)!=0 && floatLit==FLTLIT_F16)
    804                     *bufPtr++ = 's';    /* old rules of assembler */
    805                 return;
    806             }
    807             break;
    808         case 251:
    809             putChars(bufPtr, "vccz", 4);
    810             return;
    811         case 252:
    812             putChars(bufPtr, "execz", 5);
    813             return;
    814         case 253:
    815             // scc
    816             *bufPtr++ = 's';
    817             *bufPtr++ = 'c';
    818             *bufPtr++ = 'c';
    819             return;
    820         case 254:
    821             // lds
    822             *bufPtr++ = 'l';
    823             *bufPtr++ = 'd';
    824             *bufPtr++ = 's';
    825             return;
    826     }
    827    
    828     // reserved value (illegal)
    829     putChars(bufPtr, "ill_", 4);
    830     *bufPtr++ = '0'+op/100U;
    831     *bufPtr++ = '0'+(op/10U)%10U;
    832     *bufPtr++ = '0'+op%10U;
    833 }
    834 
    835 char* GCNDisasmUtils::decodeGCNOperand(GCNDisassembler& dasm, size_t codePos,
    836               RelocIter& relocIter, cxuint op, cxuint regNum, uint16_t arch,
    837               uint32_t literal, FloatLitType floatLit)
    838 {
    839     FastOutputBuffer& output = dasm.output;
    840     if (op == 255)
    841     {
    842         // if literal
    843         printLiteral(dasm, codePos, relocIter, literal, floatLit, true);
    844         return output.reserve(100);
    845     }
    846     char* bufStart = output.reserve(50);
    847     char* bufPtr = bufStart;
    848     decodeGCNOperandNoLit(dasm, op, regNum, bufPtr, arch, floatLit);
    849     output.forward(bufPtr-bufStart);
    850     return output.reserve(100);
    851 }
    852 
    853 // table of values sendmsg
    854 static const char* sendMsgCodeMessageTable[16] =
    855 {
    856     "@0",
    857     "interrupt",
    858     "gs",
    859     "gs_done",
    860     "@4", "@5", "@6", "@7", "@8", "@9", "@10", "@11", "@12", "@13", "@14", "system"
    861 };
    862 
    863 // table of values sendmsg (GCN 1.4 VEGA)
    864 static const char* sendMsgCodeMessageTableVEGA[16] =
    865 {
    866     "@0",
    867     "interrupt",
    868     "gs",
    869     "gs_done",
    870     "savewave",
    871     "stall_wave_gen",
    872     "halt_waves",
    873     "ordered_ps_done",
    874     "early_prim_dealloc",
    875     "gs_alloc_req",
    876     "get_doorbell",
    877     "@11", "@12", "@13", "@14", "system"
    878 };
    879 
    880 
    881 static const char* sendGsOpMessageTable[4] =
    882 { "nop", "cut", "emit", "emit-cut" };
    883 
    884 /* encoding routines */
    885 
    886 // add N spaces
    887 static void addSpaces(char*& bufPtr, cxuint spacesToAdd)
    888 {
    889     for (cxuint k = spacesToAdd; k>0; k--)
    890         *bufPtr++ = ' ';
    891 }
    892 
    893 // add N spaces (old style), return number
    894 static size_t addSpacesOld(char* bufPtr, cxuint spacesToAdd)
    895 {
    896     for (cxuint k = spacesToAdd; k>0; k--)
    897         *bufPtr++ = ' ';
    898     return spacesToAdd;
    899 }
    900 
    901 void GCNDisasmUtils::decodeSOPCEncoding(GCNDisassembler& dasm, size_t codePos,
    902          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    903          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
    904 {
    905     FastOutputBuffer& output = dasm.output;
    906     char* bufStart = output.reserve(90);
    907     char* bufPtr = bufStart;
    908     addSpaces(bufPtr, spacesToAdd);
    909     output.forward(bufPtr-bufStart);
    910    
    911     // form: INSTR SRC0, SRC1
    912     bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
    913                      (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
    914     *bufPtr++ = ',';
    915     *bufPtr++ = ' ';
    916     if ((gcnInsn.mode & GCN_SRC1_IMM) != 0)
    917     {
    918         // if immediate in SRC1
    919         putHexByteToBuf((insnCode>>8)&0xff, bufPtr);
    920         output.forward(bufPtr-bufStart);
    921     }
    922     else
    923     {
    924         output.forward(bufPtr-bufStart);
    925         decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>8)&0xff,
    926                (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal);
    927     }
    928 }
    929 
    930 /// about label writer - label is workaround for class hermetization
    931 void GCNDisasmUtils::decodeSOPPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    932          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    933          uint32_t literal, size_t pos)
    934 {
    935     const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
    936     FastOutputBuffer& output = dasm.output;
    937     char* bufStart = output.reserve(70);
    938     char* bufPtr = bufStart;
    939     const cxuint imm16 = insnCode&0xffff;
    940     switch(gcnInsn.mode&GCN_MASK1)
    941     {
    942         case GCN_IMM_REL:
    943         {
    944             // print relative address as label
    945             const size_t branchPos = dasm.startOffset + ((pos + int16_t(imm16))<<2);
    946             addSpaces(bufPtr, spacesToAdd);
    947             output.forward(bufPtr-bufStart);
    948             dasm.writeLocation(branchPos);
    949             return;
    950         }
    951         case GCN_IMM_LOCKS:
    952         {
    953             bool prevLock = false;
    954             addSpaces(bufPtr, spacesToAdd);
    955             const bool isf7f = (!isGCN14 && imm16==0xf7f) ||
    956                     (isGCN14 && imm16==0xcf7f);
    957             // print vmcnt only if not highest value and if 0x[c]f7f value
    958             if ((!isGCN14 && (imm16&15) != 15) ||
    959                 (isGCN14 && (imm16&0xc00f) != 0xc00f) || isf7f)
    960             {
    961                 const cxuint lockCnt = isGCN14 ?
    962                         ((imm16>>10)&0x30) + (imm16&15) : imm16&15;
    963                 putChars(bufPtr, "vmcnt(", 6);
    964                 // print value of lockCnt
    965                 const cxuint digit2 = lockCnt/10U;
    966                 if (lockCnt >= 10)
    967                     *bufPtr++ = '0'+digit2;
    968                 *bufPtr++= '0' + lockCnt-digit2*10U;
    969                 *bufPtr++ = ')';
    970                 prevLock = true;
    971             }
    972             // print only if expcnt have not highest value (7)
    973             if (((imm16>>4)&7) != 7 || isf7f)
    974             {
    975                 if (prevLock)
    976                 {
    977                     // print & before previous lock: vmcnt()
    978                     *bufPtr++ = ' ';
    979                     *bufPtr++ = '&';
    980                     *bufPtr++ = ' ';
    981                 }
    982                 putChars(bufPtr, "expcnt(", 7);
    983                 // print value
    984                 *bufPtr++ = '0' + ((imm16>>4)&7);
    985                 *bufPtr++ = ')';
    986                 prevLock = true;
    987             }
    988             // print only if lgkmcnt have not highest value (15)
    989             if (((imm16>>8)&15) != 15 || isf7f)
    990             {
    991                 /* LGKMCNT bits is 4 (5????) */
    992                 const cxuint lockCnt = (imm16>>8)&15;
    993                 if (prevLock)
    994                 {
    995                     // print & before previous lock: vmcnt()
    996                     *bufPtr++ = ' ';
    997                     *bufPtr++ = '&';
    998                     *bufPtr++ = ' ';
    999                 }
    1000                 putChars(bufPtr, "lgkmcnt(", 8);
    1001                 const cxuint digit2 = lockCnt/10U;
    1002                 if (lockCnt >= 10)
    1003                     *bufPtr++ = '0'+digit2;
    1004                 *bufPtr++= '0' + lockCnt-digit2*10U;
    1005                 *bufPtr++ = ')';
    1006                 prevLock = true;
    1007             }
    1008             if ((!isGCN14 && (imm16&0xf080) != 0) || (isGCN14 && (imm16&0x3080) != 0))
    1009             {
    1010                 /* additional info about imm16 */
    1011                 if (prevLock)
    1012                 {
    1013                     *bufPtr++ = ' ';
    1014                     *bufPtr++ = ':';
    1015                 }
    1016                 bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
    1017             }
    1018             break;
    1019         }
    1020         case GCN_IMM_MSGS:
    1021         {
    1022             cxuint illMask = 0xfff0;
    1023             addSpaces(bufPtr, spacesToAdd);
    1024            
    1025             // print sendmsg
    1026             putChars(bufPtr, "sendmsg(", 8);
    1027             const cxuint msgType = imm16&15;
    1028             const char* msgName = (isGCN14 ? sendMsgCodeMessageTableVEGA[msgType] :
    1029                     sendMsgCodeMessageTable[msgType]);
    1030             cxuint minUnknownMsgType = isGCN14 ? 11 : 4;
    1031             if ((arch & ARCH_RX3X0) != 0 && msgType == 4)
    1032             {
    1033                 msgName = "savewave"; // 4 - savewave
    1034                 minUnknownMsgType = 5;
    1035             }
    1036             // put message name to buffer
    1037             while (*msgName != 0)
    1038                 *bufPtr++ = *msgName++;
    1039            
    1040             // if also some arguments supplied (gsops)
    1041             if ((msgType&14) == 2 || (msgType >= minUnknownMsgType && msgType <= 14) ||
    1042                 (imm16&0x3f0) != 0) // gs ops
    1043             {
    1044                 *bufPtr++ = ',';
    1045                 *bufPtr++ = ' ';
    1046                 illMask = 0xfcc0; // set new illegal mask of bits
    1047                 const cxuint gsopId = (imm16>>4)&3;
    1048                 const char* gsopName = sendGsOpMessageTable[gsopId];
    1049                 // put gsop name to buffer
    1050                 while (*gsopName != 0)
    1051                     *bufPtr++ = *gsopName++;
    1052                 if (gsopId!=0 || ((imm16>>8)&3)!=0)
    1053                 {
    1054                     *bufPtr++ = ',';
    1055                     *bufPtr++ = ' ';
    1056                     // print gsop value
    1057                     *bufPtr++ = '0' + ((imm16>>8)&3);
    1058                 }
    1059             }
    1060             *bufPtr++ = ')';
    1061             // if some bits is not zero (illegal value)
    1062             if ((imm16&illMask) != 0)
    1063             {
    1064                 *bufPtr++ = ' ';
    1065                 *bufPtr++ = ':';
    1066                 bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
    1067             }
    1068             break;
    1069         }
    1070         case GCN_IMM_NONE:
    1071             if (imm16 != 0)
    1072             {
    1073                 addSpaces(bufPtr, spacesToAdd);
    1074                 bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
    1075             }
    1076             break;
    1077         default:
    1078             addSpaces(bufPtr, spacesToAdd);
    1079             bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
    1080             break;
    1081     }
    1082     output.forward(bufPtr-bufStart);
    1083 }
    1084 
    1085 void GCNDisasmUtils::decodeSOP1Encoding(GCNDisassembler& dasm, size_t codePos,
    1086          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    1087          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
    1088 {
    1089     FastOutputBuffer& output = dasm.output;
    1090     char* bufStart = output.reserve(80);
    1091     char* bufPtr = bufStart;
    1092     addSpaces(bufPtr, spacesToAdd);
    1093     bool isDst = (gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE;
    1094     // print destination if instruction have it
    1095     if (isDst)
    1096     {
    1097         output.forward(bufPtr-bufStart);
    1098         bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
    1099                          (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
    1100     }
    1101    
    1102     if ((gcnInsn.mode & GCN_MASK1) != GCN_SRC_NONE)
    1103     {
    1104         if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
    1105         {
    1106             // put ',' if destination and source
    1107             *bufPtr++ = ',';
    1108             *bufPtr++ = ' ';
    1109         }
    1110         // put SRC1
    1111         output.forward(bufPtr-bufStart);
    1112         bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
    1113                          (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
    1114     }
    1115     else if ((insnCode&0xff) != 0)
    1116     {
    1117         // print value, if some are not used, but values is not default
    1118         putChars(bufPtr," ssrc=", 6);
    1119         bufPtr += itocstrCStyle((insnCode&0xff), bufPtr, 6, 16);
    1120     }
    1121     // print value, if some are not used, but values is not default
    1122     if (!isDst && ((insnCode>>16)&0x7f) != 0)
    1123     {
    1124         putChars(bufPtr, " sdst=", 6);
    1125         bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
    1126     }
    1127     output.forward(bufPtr-bufStart);
    1128 }
    1129 
    1130 void GCNDisasmUtils::decodeSOP2Encoding(GCNDisassembler& dasm, size_t codePos,
    1131          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    1132          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
    1133 {
    1134     FastOutputBuffer& output = dasm.output;
    1135     char* bufStart = output.reserve(90);
    1136     char* bufPtr = bufStart;
    1137     addSpaces(bufPtr, spacesToAdd);
    1138     if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_NONE)
    1139     {
    1140         // print destination
    1141         output.forward(bufPtr-bufStart);
    1142         bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
    1143                          (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
    1144         *bufPtr++ = ',';
    1145         *bufPtr++ = ' ';
    1146     }
    1147     // print SRC0
    1148     output.forward(bufPtr-bufStart);
    1149     bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, insnCode&0xff,
    1150                      (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal);
    1151     *bufPtr++ = ',';
    1152     *bufPtr++ = ' ';
    1153     // print SRC1
    1154     output.forward(bufPtr-bufStart);
    1155     bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>8)&0xff,
    1156                  (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch, literal);
    1157    
    1158     // print value, if some are not used, but values is not default
    1159     if ((gcnInsn.mode & GCN_MASK1) == GCN_DST_NONE && ((insnCode>>16)&0x7f) != 0)
    1160     {
    1161         putChars(bufPtr, " sdst=", 6);
    1162         bufPtr += itocstrCStyle(((insnCode>>16)&0x7f), bufPtr, 6, 16);
    1163     }
    1164     output.forward(bufPtr-bufStart);
    1165 }
    1166 
    1167 // table hwreg names
    1168 static const char* hwregNames[20] =
    1169 {
    1170     "@0", "mode", "status", "trapsts",
    1171     "hw_id", "gpr_alloc", "lds_alloc", "ib_sts",
    1172     "pc_lo", "pc_hi", "inst_dw0", "inst_dw1",
    1173     "ib_dbg0", "ib_dbg1", "flush_ib", "sh_mem_bases",
    1174     "sq_shader_tba_lo", "sq_shader_tba_hi",
    1175     "sq_shader_tma_lo", "sq_shader_tma_hi"
    1176 };
    1177 
    1178 /// about label writer - label is workaround for class hermetization
    1179 void GCNDisasmUtils::decodeSOPKEncoding(GCNDisassembler& dasm, size_t codePos,
    1180          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    1181          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal)
    1182 {
    1183     FastOutputBuffer& output = dasm.output;
    1184     char* bufStart = output.reserve(90);
    1185     char* bufPtr = bufStart;
    1186     addSpaces(bufPtr, spacesToAdd);
    1187     if ((gcnInsn.mode & GCN_IMM_DST) == 0)
    1188     {
    1189         // if normal destination
    1190         output.forward(bufPtr-bufStart);
    1191         bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter, (insnCode>>16)&0x7f,
    1192                          (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
    1193         *bufPtr++ = ',';
    1194         *bufPtr++ = ' ';
    1195     }
    1196     const cxuint imm16 = insnCode&0xffff;
    1197     if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_REL)
    1198     {
    1199         // print relative address (as label)
    1200         const size_t branchPos = dasm.startOffset + ((codePos + int16_t(imm16))<<2);
    1201         output.forward(bufPtr-bufStart);
    1202         dasm.writeLocation(branchPos);
    1203         bufPtr = bufStart = output.reserve(60);
    1204     }
    1205     else if ((gcnInsn.mode&GCN_MASK1) == GCN_IMM_SREG)
    1206     {
    1207         // print hwreg()
    1208         putChars(bufPtr, "hwreg(", 6);
    1209         const cxuint hwregId = imm16&0x3f;
    1210         cxuint hwregNamesNum = 13 + ((arch&ARCH_GCN_1_2_4)!=0);
    1211         if ((arch&ARCH_RXVEGA) != 0)
    1212             hwregNamesNum = 20;
    1213         if (hwregId < hwregNamesNum)
    1214             putChars(bufPtr, hwregNames[hwregId], ::strlen(hwregNames[hwregId]));
    1215         else
    1216         {
    1217             // parametrized hwreg: hwreg(@0
    1218             const cxuint digit2 = hwregId/10U;
    1219             *bufPtr++ = '@';
    1220             *bufPtr++ = '0' + digit2;
    1221             *bufPtr++ = '0' + hwregId - digit2*10U;
    1222         }
    1223         *bufPtr++ = ',';
    1224         *bufPtr++ = ' ';
    1225         // start bit
    1226         putByteToBuf((imm16>>6)&31, bufPtr);
    1227         *bufPtr++ = ',';
    1228         *bufPtr++ = ' ';
    1229         // size in bits
    1230         putByteToBuf(((imm16>>11)&31)+1, bufPtr);
    1231         *bufPtr++ = ')';
    1232     }
    1233     else
    1234         bufPtr += itocstrCStyle(imm16, bufPtr, 11, 16);
    1235    
    1236     if (gcnInsn.mode & GCN_IMM_DST)
    1237     {
    1238         *bufPtr++ = ',';
    1239         *bufPtr++ = ' ';
    1240         // print value, if some are not used, but values is not default
    1241         if (gcnInsn.mode & GCN_SOPK_CONST)
    1242         {
    1243             // for S_SETREG_IMM32_B32
    1244             bufPtr += itocstrCStyle(literal, bufPtr, 11, 16);
    1245             if (((insnCode>>16)&0x7f) != 0)
    1246             {
    1247                 putChars(bufPtr, " sdst=", 6);
    1248                 bufPtr += itocstrCStyle((insnCode>>16)&0x7f, bufPtr, 6, 16);
    1249             }
    1250         }
    1251         else
    1252         {
    1253             // for s_setreg_b32, print destination as source
    1254             output.forward(bufPtr-bufStart);
    1255             bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter,
    1256                      (insnCode>>16)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1, arch);
    1257         }
    1258     }
    1259     output.forward(bufPtr-bufStart);
    1260 }
    1261 
    1262 void GCNDisasmUtils::decodeSMRDEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    1263              uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode)
    1264 {
    1265     FastOutputBuffer& output = dasm.output;
    1266     char* bufStart = output.reserve(100);
    1267     char* bufPtr = bufStart;
    1268     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1269     bool useDst = false;
    1270     bool useOthers = false;
    1271    
    1272     bool spacesAdded = false;
    1273     if (mode1 == GCN_SMRD_ONLYDST)
    1274     {
    1275         // print only destination
    1276         addSpaces(bufPtr, spacesToAdd);
    1277         decodeGCNOperandNoLit(dasm, (insnCode>>15)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
    1278                          bufPtr, arch);
    1279         useDst = true;
    1280         spacesAdded = true;
    1281     }
    1282     else if (mode1 != GCN_ARG_NONE)
    1283     {
    1284         const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
    1285         addSpaces(bufPtr, spacesToAdd);
    1286         // print destination (1,2,4,8 or 16 registers)
    1287         decodeGCNOperandNoLit(dasm, (insnCode>>15)&0x7f, dregsNum, bufPtr, arch);
    1288         *bufPtr++ = ',';
    1289         *bufPtr++ = ' ';
    1290         // print SBASE (base address registers) (address or resource)
    1291         decodeGCNOperandNoLit(dasm, (insnCode>>8)&0x7e, (gcnInsn.mode&GCN_SBASE4)?4:2,
    1292                           bufPtr, arch);
    1293         *bufPtr++ = ',';
    1294         *bufPtr++ = ' ';
    1295         if (insnCode&0x100) // immediate value
    1296             bufPtr += itocstrCStyle(insnCode&0xff, bufPtr, 11, 16);
    1297         else // S register
    1298             decodeGCNOperandNoLit(dasm, insnCode&0xff, 1, bufPtr, arch);
    1299         // set what is printed
    1300         useDst = true;
    1301         useOthers = true;
    1302         spacesAdded = true;
    1303     }
    1304    
    1305     // print value, if some are not used, but values is not default
    1306     if (!useDst && (insnCode & 0x3f8000U) != 0)
    1307     {
    1308         addSpaces(bufPtr, spacesToAdd-1);
    1309         spacesAdded = true;
    1310         putChars(bufPtr, " sdst=", 6);
    1311         bufPtr += itocstrCStyle((insnCode>>15)&0x7f, bufPtr, 6, 16);
    1312     }
    1313     if (!useOthers && (insnCode & 0x7e00U)!=0)
    1314     {
    1315         if (!spacesAdded)
    1316             addSpaces(bufPtr, spacesToAdd-1);
    1317         spacesAdded = true;
    1318         putChars(bufPtr, " sbase=", 7);
    1319         bufPtr += itocstrCStyle((insnCode>>9)&0x3f, bufPtr, 6, 16);
    1320     }
    1321     if (!useOthers && (insnCode & 0xffU)!=0)
    1322     {
    1323         if (!spacesAdded)
    1324             addSpaces(bufPtr, spacesToAdd-1);
    1325         spacesAdded = true;
    1326         putChars(bufPtr, " offset=", 8);
    1327         bufPtr += itocstrCStyle(insnCode&0xff, bufPtr, 6, 16);
    1328     }
    1329     if (!useOthers && (insnCode & 0x100U)!=0)
    1330     {
    1331         if (!spacesAdded)
    1332             addSpaces(bufPtr, spacesToAdd-1);
    1333         spacesAdded = true;
    1334         putChars(bufPtr, " imm=1", 6);
    1335     }
    1336     output.forward(bufPtr-bufStart);
    1337 }
    1338 
    1339 void GCNDisasmUtils::decodeSMEMEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    1340          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    1341          uint32_t insnCode2)
    1342 {
    1343     FastOutputBuffer& output = dasm.output;
    1344     char* bufStart = output.reserve(120);
    1345     char* bufPtr = bufStart;
    1346     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1347     bool useDst = false;
    1348     bool useOthers = false;
    1349     bool spacesAdded = false;
    1350     const bool isGCN14 = ((arch&ARCH_RXVEGA) != 0);
    1351     bool printOffset = false;
    1352    
    1353     if (mode1 == GCN_SMRD_ONLYDST)
    1354     {
    1355         // print only destination
    1356         addSpaces(bufPtr, spacesToAdd);
    1357         decodeGCNOperandNoLit(dasm, (insnCode>>6)&0x7f, (gcnInsn.mode&GCN_REG_DST_64)?2:1,
    1358                          bufPtr, arch);
    1359         useDst = true;
    1360         spacesAdded = true;
    1361     }
    1362     else if (mode1 != GCN_ARG_NONE)
    1363     {
    1364         const cxuint dregsNum = 1<<((gcnInsn.mode & GCN_DSIZE_MASK)>>GCN_SHIFT2);
    1365         addSpaces(bufPtr, spacesToAdd);
    1366         if (!(mode1 & GCN_SMEM_NOSDATA)) {
    1367             if (mode1 & GCN_SMEM_SDATA_IMM)
    1368                 // print immediate value
    1369                 putHexByteToBuf((insnCode>>6)&0x7f, bufPtr);
    1370             else
    1371                 // print destination (1,2,4,8 or 16 registers)
    1372                 decodeGCNOperandNoLit(dasm, (insnCode>>6)&0x7f, dregsNum, bufPtr , arch);
    1373             *bufPtr++ = ',';
    1374             *bufPtr++ = ' ';
    1375             useDst = true;
    1376         }
    1377         // print SBASE (base address registers) (address or resource)
    1378         decodeGCNOperandNoLit(dasm, (insnCode<<1)&0x7e, (gcnInsn.mode&GCN_SBASE4)?4:2,
    1379                           bufPtr, arch);
    1380         *bufPtr++ = ',';
    1381         *bufPtr++ = ' ';
    1382         if (insnCode&0x20000) // immediate value
    1383         {
    1384             if (isGCN14 && (insnCode & 0x4000) != 0)
    1385             {
    1386                 // last 8-bit in second dword
    1387                 decodeGCNOperandNoLit(dasm, (insnCode2>>25), 1, bufPtr , arch);
    1388                 printOffset = true;
    1389             }
    1390             else
    1391             {
    1392                 // print SOFFSET
    1393                 uint32_t immMask =  isGCN14 ? 0x1fffff : 0xfffff;
    1394                 bufPtr += itocstrCStyle(insnCode2 & immMask, bufPtr, 11, 16);
    1395             }
    1396         }
    1397         else // SOFFSET register
    1398         {
    1399             if (isGCN14 && (insnCode & 0x4000) != 0)
    1400                 decodeGCNOperandNoLit(dasm, insnCode2>>25, 1, bufPtr, arch);
    1401             else
    1402                 decodeGCNOperandNoLit(dasm, insnCode2&0xff, 1, bufPtr, arch);
    1403         }
    1404         useOthers = true;
    1405         spacesAdded = true;
    1406     }
    1407    
    1408     if ((insnCode & 0x10000) != 0)
    1409     {
    1410         if (!spacesAdded)
    1411             addSpaces(bufPtr, spacesToAdd-1);
    1412         spacesAdded = true;
    1413         // print GLC modifier
    1414         putChars(bufPtr, " glc", 4);
    1415     }
    1416    
    1417     if (isGCN14 && (insnCode & 0x8000) != 0)
    1418     {
    1419         if (!spacesAdded)
    1420             addSpaces(bufPtr, spacesToAdd-1);
    1421         spacesAdded = true;
    1422         // print NV modifier
    1423         putChars(bufPtr, " nv", 3);
    1424     }
    1425    
    1426     if (printOffset)
    1427     {
    1428         // GCN 1.4 extra OFFSET
    1429         if (!spacesAdded)
    1430             addSpaces(bufPtr, spacesToAdd-1);
    1431         spacesAdded = true;
    1432         putChars(bufPtr, " offset:", 8);
    1433         bufPtr += itocstrCStyle(insnCode2 & 0x1fffff, bufPtr, 11, 16);
    1434     }
    1435    
    1436     // print value, if some are not used, but values is not default
    1437     if (!useDst && (insnCode & 0x1fc0U) != 0)
    1438     {
    1439         if (!spacesAdded)
    1440             addSpaces(bufPtr, spacesToAdd-1);
    1441         spacesAdded = true;
    1442         putChars(bufPtr, " sdata=", 7);
    1443         bufPtr += itocstrCStyle((insnCode>>6)&0x7f, bufPtr, 6, 16);
    1444     }
    1445     if (!useOthers && (insnCode & 0x3fU)!=0)
    1446     {
    1447         if (!spacesAdded)
    1448             addSpaces(bufPtr, spacesToAdd-1);
    1449         spacesAdded = true;
    1450         putChars(bufPtr, " sbase=", 7);
    1451         bufPtr += itocstrCStyle(insnCode&0x3f, bufPtr, 6, 16);
    1452     }
    1453     if (!useOthers && insnCode2!=0)
    1454     {
    1455         if (!spacesAdded)
    1456             addSpaces(bufPtr, spacesToAdd-1);
    1457         spacesAdded = true;
    1458         putChars(bufPtr, " offset=", 8);
    1459         bufPtr += itocstrCStyle(insnCode2, bufPtr, 12, 16);
    1460     }
    1461     if (!useOthers && (insnCode & 0x20000U)!=0)
    1462     {
    1463         if (!spacesAdded)
    1464             addSpaces(bufPtr, spacesToAdd-1);
    1465         spacesAdded = true;
    1466         putChars(bufPtr, " imm=1", 6);
    1467     }
    1468    
    1469     output.forward(bufPtr-bufStart);
    1470 }
    1471 
    1472 // temporary structure to store operand modifiers and operand SRC0
    1473 struct CLRX_INTERNAL VOPExtraWordOut
    1474 {
    1475     uint16_t src0;
    1476     bool sextSrc0;
    1477     bool negSrc0;
    1478     bool absSrc0;
    1479     bool sextSrc1;
    1480     bool negSrc1;
    1481     bool absSrc1;
    1482     bool scalarSrc1;
    1483 };
    1484 
    1485 // SDWA SEL field value names
    1486 static const char* sdwaSelChoicesTbl[] =
    1487 {
    1488     "byte0", "byte1", "byte2", "byte3", "word0", "word1", nullptr, "invalid"
    1489 };
    1490 
    1491 // SDWA UNUSED field value names
    1492 static const char* sdwaDstUnusedTbl[] =
    1493 {
    1494     nullptr, "sext", "preserve", "invalid"
    1495 };
    1496 
    1497 /* returns mask of abs,neg,sext for src0 and src1 argument and src0 register */
    1498 static inline VOPExtraWordOut decodeVOPSDWAFlags(uint32_t insnCode2, uint16_t arch)
    1499 {
    1500     const bool isGCN14 = (arch & ARCH_RXVEGA)!=0;
    1501     return { uint16_t((insnCode2&0xff) +
    1502         ((!isGCN14 || (insnCode2 & (1U<<23))==0) ? 256 : 0)),
    1503         (insnCode2&(1U<<19))!=0, (insnCode2&(1U<<20))!=0, (insnCode2&(1U<<21))!=0,
    1504         (insnCode2&(1U<<27))!=0, (insnCode2&(1U<<28))!=0, (insnCode2&(1U<<29))!=0,
    1505         isGCN14 && ((insnCode2&(1U<<31))!=0) };
    1506 }
    1507 
    1508 // decode and print VOP SDWA encoding
    1509 static void decodeVOPSDWA(FastOutputBuffer& output, uint16_t arch, uint32_t insnCode2,
    1510           bool src0Used, bool src1Used, bool vopc = false)
    1511 {
    1512     char* bufStart = output.reserve(100);
    1513     char* bufPtr = bufStart;
    1514     const bool isGCN14 = ((arch&ARCH_RXVEGA) != 0);
    1515     cxuint dstSel = 6;
    1516     cxuint dstUnused = 0;
    1517     if (!isGCN14 || !vopc)
    1518     {
    1519         // not VEGA or not VOPC
    1520         dstSel = (insnCode2>>8)&7;
    1521         dstUnused = (insnCode2>>11)&3;
    1522     }
    1523     const cxuint src0Sel = (insnCode2>>16)&7;
    1524     const cxuint src1Sel = (insnCode2>>24)&7;
    1525    
    1526     if (!isGCN14 || !vopc)
    1527     {
    1528         // not VEGA or not VOPC
    1529         if (isGCN14 && (insnCode2 & 0xc000U) != 0)
    1530         {
    1531             cxuint omod = (insnCode2>>14)&3;
    1532             const char* omodStr = (omod==3)?" div:2":(omod==2)?" mul:4":" mul:2";
    1533             putChars(bufPtr, omodStr, 6);
    1534         }
    1535         if (insnCode2 & 0x2000)
    1536             putChars(bufPtr, " clamp", 6);
    1537        
    1538         // print dst_sel:XXXX
    1539         if (dstSel != 6)
    1540         {
    1541             putChars(bufPtr, " dst_sel:", 9);
    1542             putChars(bufPtr, sdwaSelChoicesTbl[dstSel],
    1543                     ::strlen(sdwaSelChoicesTbl[dstSel]));
    1544         }
    1545         // print dst_unused:XXX
    1546         if (dstUnused!=0)
    1547         {
    1548             putChars(bufPtr, " dst_unused:", 12);
    1549             putChars(bufPtr, sdwaDstUnusedTbl[dstUnused],
    1550                     ::strlen(sdwaDstUnusedTbl[dstUnused]));
    1551         }
    1552     }
    1553     // print src0_sel and src1_sel if used
    1554     if (src0Sel!=6 && src0Used)
    1555     {
    1556         putChars(bufPtr, " src0_sel:", 10);
    1557         putChars(bufPtr, sdwaSelChoicesTbl[src0Sel],
    1558                  ::strlen(sdwaSelChoicesTbl[src0Sel]));
    1559     }
    1560     if (src1Sel!=6 && src1Used)
    1561     {
    1562         putChars(bufPtr, " src1_sel:", 10);
    1563         putChars(bufPtr, sdwaSelChoicesTbl[src1Sel],
    1564                  ::strlen(sdwaSelChoicesTbl[src1Sel]));
    1565     }
    1566     // unused but fields
    1567     if (!src0Used)
    1568     {
    1569         if ((insnCode2&(1U<<19))!=0)
    1570             putChars(bufPtr, " sext0", 6);
    1571         if ((insnCode2&(1U<<20))!=0)
    1572             putChars(bufPtr, " neg0", 5);
    1573         if ((insnCode2&(1U<<21))!=0)
    1574             putChars(bufPtr, " abs0", 5);
    1575     }
    1576     if (!src1Used)
    1577     {
    1578         if ((insnCode2&(1U<<27))!=0)
    1579             putChars(bufPtr, " sext1", 6);
    1580         if ((insnCode2&(1U<<28))!=0)
    1581             putChars(bufPtr, " neg1", 5);
    1582         if ((insnCode2&(1U<<29))!=0)
    1583             putChars(bufPtr, " abs1", 5);
    1584     }
    1585    
    1586     // add SDWA encoding specifier at end if needed (to avoid ambiguity)
    1587     if (((isGCN14 && vopc) || (dstSel==6 && dstUnused==0)) &&
    1588         src0Sel==6 && (insnCode2&(1U<<19))==0 && src1Sel==6 && (insnCode2&(1U<<27))==0)
    1589         putChars(bufPtr, " sdwa", 5);
    1590    
    1591     output.forward(bufPtr-bufStart);
    1592 }
    1593 
    1594 /// DPP CTRL value table (only
    1595 static const char* dppCtrl130Tbl[] =
    1596 {
    1597     " wave_shl", nullptr, nullptr, nullptr,
    1598     " wave_rol", nullptr, nullptr, nullptr,
    1599     " wave_shr", nullptr, nullptr, nullptr,
    1600     " wave_ror", nullptr, nullptr, nullptr,
    1601     " row_mirror", " row_half_mirror", " row_bcast15", " row_bcast31"
    1602 };
    1603 
    1604 /* returns mask of abs,neg,sext for src0 and src1 argument and src0 register */
    1605 static inline VOPExtraWordOut decodeVOPDPPFlags(uint32_t insnCode2)
    1606 {
    1607     return { uint16_t((insnCode2&0xff)+256),
    1608         false, (insnCode2&(1U<<20))!=0, (insnCode2&(1U<<21))!=0,
    1609         false, (insnCode2&(1U<<22))!=0, (insnCode2&(1U<<23))!=0, false };
    1610 }
    1611 
    1612 static void decodeVOPDPP(FastOutputBuffer& output, uint32_t insnCode2,
    1613         bool src0Used, bool src1Used)
    1614 {
    1615     char* bufStart = output.reserve(110);
    1616     char* bufPtr = bufStart;
    1617     const cxuint dppCtrl = (insnCode2>>8)&0x1ff;
    1618    
    1619     if (dppCtrl<256)
    1620     {
    1621         // print quadperm: quad_perm[A:B:C:D] A,B,C,D - 2-bit values
    1622         putChars(bufPtr, " quad_perm:[", 12);
    1623         *bufPtr++ = '0' + (dppCtrl&3);
    1624         *bufPtr++ = ',';
    1625         *bufPtr++ = '0' + ((dppCtrl>>2)&3);
    1626         *bufPtr++ = ',';
    1627         *bufPtr++ = '0' + ((dppCtrl>>4)&3);
    1628         *bufPtr++ = ',';
    1629         *bufPtr++ = '0' + ((dppCtrl>>6)&3);
    1630         *bufPtr++ = ']';
    1631     }
    1632     else if ((dppCtrl >= 0x101 && dppCtrl <= 0x12f) && ((dppCtrl&0xf) != 0))
    1633     {
    1634         // row_shl, row_shr or row_ror
    1635         if ((dppCtrl&0xf0) == 0)
    1636             putChars(bufPtr, " row_shl:", 9);
    1637         else if ((dppCtrl&0xf0) == 16)
    1638             putChars(bufPtr, " row_shr:", 9);
    1639         else
    1640             putChars(bufPtr, " row_ror:", 9);
    1641         // print shift
    1642         putByteToBuf(dppCtrl&0xf, bufPtr);
    1643     }
    1644     else if (dppCtrl >= 0x130 && dppCtrl <= 0x143 && dppCtrl130Tbl[dppCtrl-0x130]!=nullptr)
    1645         // print other dpp modifier
    1646         putChars(bufPtr, dppCtrl130Tbl[dppCtrl-0x130],
    1647                  ::strlen(dppCtrl130Tbl[dppCtrl-0x130]));
    1648     // otherwise print value of dppctrl (illegal value)
    1649     else if (dppCtrl != 0x100)
    1650     {
    1651         putChars(bufPtr, " dppctrl:", 9);
    1652         bufPtr += itocstrCStyle(dppCtrl, bufPtr, 10, 16);
    1653     }
    1654    
    1655     if (insnCode2 & (0x80000U)) // bound ctrl
    1656         putChars(bufPtr, " bound_ctrl", 11);
    1657    
    1658     // print bank_mask and row_mask
    1659     putChars(bufPtr, " bank_mask:", 11);
    1660     putByteToBuf((insnCode2>>24)&0xf, bufPtr);
    1661     putChars(bufPtr, " row_mask:", 10);
    1662     putByteToBuf((insnCode2>>28)&0xf, bufPtr);
    1663     // unused but fields
    1664     if (!src0Used)
    1665     {
    1666         if ((insnCode2&(1U<<20))!=0)
    1667             putChars(bufPtr, " neg0", 5);
    1668         if ((insnCode2&(1U<<21))!=0)
    1669             putChars(bufPtr, " abs0", 5);
    1670     }
    1671     if (!src1Used)
    1672     {
    1673         if ((insnCode2&(1U<<22))!=0)
    1674             putChars(bufPtr, " neg1", 5);
    1675         if ((insnCode2&(1U<<23))!=0)
    1676             putChars(bufPtr, " abs1", 5);
    1677     }
    1678    
    1679     output.forward(bufPtr-bufStart);
    1680 }
    1681 
    1682 void GCNDisasmUtils::decodeVOPCEncoding(GCNDisassembler& dasm, size_t codePos,
    1683          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    1684          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
    1685          FloatLitType displayFloatLits)
    1686 {
    1687     FastOutputBuffer& output = dasm.output;
    1688     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    1689     char* bufStart = output.reserve(120);
    1690     char* bufPtr = bufStart;
    1691     addSpaces(bufPtr, spacesToAdd);
    1692    
    1693     const cxuint src0Field = (insnCode&0x1ff);
    1694     // extra flags are zeroed by default
    1695     VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
    1696     if ((arch & ARCH_RXVEGA) != 0 && src0Field==0xf9 && (literal & 0x8000) != 0)
    1697     {
    1698         // SDWAB replacement of SDST
    1699         output.forward(bufPtr-bufStart);
    1700         bufPtr = bufStart = decodeGCNOperand(dasm, codePos, relocIter,
    1701                             (literal>>8)&0x7f, 2, arch);
    1702         *bufPtr++ = ',';
    1703         *bufPtr++ = ' ';
    1704     }
    1705     else // just vcc
    1706         putChars(bufPtr, "vcc, ", 5);
    1707    
    1708     if (isGCN12)
    1709     {
    1710         // return VOP SDWA/DPP flags for operands
    1711         if (src0Field == 0xf9)
    1712             extraFlags = decodeVOPSDWAFlags(literal, arch);
    1713         else if (src0Field == 0xfa)
    1714             extraFlags = decodeVOPDPPFlags(literal);
    1715         else
    1716             extraFlags.src0 = src0Field;
    1717     }
    1718     else
    1719         extraFlags.src0 = src0Field;
    1720    
    1721     // apply sext(), negation and abs() if applied
    1722     if (extraFlags.sextSrc0)
    1723         putChars(bufPtr, "sext(", 5);
    1724     if (extraFlags.negSrc0)
    1725         *bufPtr++ = '-';
    1726     if (extraFlags.absSrc0)
    1727         putChars(bufPtr, "abs(", 4);
    1728    
    1729     output.forward(bufPtr-bufStart);
    1730     // print SRC0
    1731     bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
    1732                  (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
    1733     // closing for abs and sext
    1734     if (extraFlags.absSrc0)
    1735         *bufPtr++ = ')';
    1736     if (extraFlags.sextSrc0)
    1737         *bufPtr++ = ')';
    1738     *bufPtr++ = ',';
    1739     *bufPtr++ = ' ';
    1740    
    1741     // apply sext(), negation and abs() if applied
    1742     if (extraFlags.sextSrc1)
    1743         putChars(bufPtr, "sext(", 5);
    1744    
    1745     if (extraFlags.negSrc1)
    1746         *bufPtr++ = '-';
    1747     if (extraFlags.absSrc1)
    1748         putChars(bufPtr, "abs(", 4);
    1749    
    1750     // print SRC1
    1751     decodeGCNOperandNoLit(dasm, ((insnCode>>9)&0xff) + (extraFlags.scalarSrc1 ? 0 : 256),
    1752                 (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr, arch);
    1753     // closing for abs and sext
    1754     if (extraFlags.absSrc1)
    1755         *bufPtr++ = ')';
    1756     if (extraFlags.sextSrc1)
    1757         *bufPtr++ = ')';
    1758    
    1759     output.forward(bufPtr-bufStart);
    1760     if (isGCN12)
    1761     {
    1762         // print extra SDWA/DPP modifiers
    1763         if (src0Field == 0xf9)
    1764             decodeVOPSDWA(output, arch, literal, true, true, true);
    1765         else if (src0Field == 0xfa)
    1766             decodeVOPDPP(output, literal, true, true);
    1767     }
    1768 }
    1769 
    1770 void GCNDisasmUtils::decodeVOP1Encoding(GCNDisassembler& dasm, size_t codePos,
    1771          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    1772          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
    1773          FloatLitType displayFloatLits)
    1774 {
    1775     FastOutputBuffer& output = dasm.output;
    1776     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    1777     char* bufStart = output.reserve(130);
    1778     char* bufPtr = bufStart;
    1779    
    1780     const cxuint src0Field = (insnCode&0x1ff);
    1781     // extra flags are zeroed by default
    1782     VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
    1783    
    1784     if (isGCN12)
    1785     {
    1786         // return extra flags from SDWA/DPP encoding
    1787         if (src0Field == 0xf9)
    1788             extraFlags = decodeVOPSDWAFlags(literal, arch);
    1789         else if (src0Field == 0xfa)
    1790             extraFlags = decodeVOPDPPFlags(literal);
    1791         else
    1792             extraFlags.src0 = src0Field;
    1793     }
    1794     else
    1795         extraFlags.src0 = src0Field;
    1796    
    1797     bool argsUsed = true;
    1798     if ((gcnInsn.mode & GCN_MASK1) != GCN_VOP_ARG_NONE)
    1799     {
    1800         addSpaces(bufPtr, spacesToAdd);
    1801         if ((gcnInsn.mode & GCN_MASK1) != GCN_DST_SGPR)
    1802             // print DST as SGPR
    1803             decodeGCNVRegOperand(((insnCode>>17)&0xff),
    1804                      (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr);
    1805         else
    1806             // print DST as normal VGPR
    1807             decodeGCNOperandNoLit(dasm, ((insnCode>>17)&0xff),
    1808                           (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr, arch);
    1809         *bufPtr++ = ',';
    1810         *bufPtr++ = ' ';
    1811         // apply sext, negation and abs if supplied
    1812         if (extraFlags.sextSrc0)
    1813             putChars(bufPtr, "sext(", 5);
    1814        
    1815         if (extraFlags.negSrc0)
    1816             *bufPtr++ = '-';
    1817         if (extraFlags.absSrc0)
    1818             putChars(bufPtr, "abs(", 4);
    1819         output.forward(bufPtr-bufStart);
    1820         // print SRC0
    1821         bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
    1822                      (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
    1823         // closing sext and abs
    1824         if (extraFlags.absSrc0)
    1825             *bufPtr++ = ')';
    1826         if (extraFlags.sextSrc0)
    1827             *bufPtr++ = ')';
    1828     }
    1829     else if ((insnCode & 0x1fe01ffU) != 0)
    1830     {
    1831         // unused, but set fields
    1832         addSpaces(bufPtr, spacesToAdd);
    1833         if ((insnCode & 0x1fe0000U) != 0)
    1834         {
    1835             putChars(bufPtr, "vdst=", 5);
    1836             bufPtr += itocstrCStyle((insnCode>>17)&0xff, bufPtr, 6, 16);
    1837             if ((insnCode & 0x1ff) != 0)
    1838                 *bufPtr++ = ' ';
    1839         }
    1840         if ((insnCode & 0x1ff) != 0)
    1841         {
    1842             putChars(bufPtr, "src0=", 5);
    1843             bufPtr += itocstrCStyle(insnCode&0x1ff, bufPtr, 6, 16);
    1844         }
    1845         argsUsed = false;
    1846     }
    1847     output.forward(bufPtr-bufStart);
    1848     if (isGCN12)
    1849     {
    1850         // print extra SDWA/DPP modifiers
    1851         if (src0Field == 0xf9)
    1852             decodeVOPSDWA(output, arch, literal, argsUsed, false);
    1853         else if (src0Field == 0xfa)
    1854             decodeVOPDPP(output, literal, argsUsed, false);
    1855     }
    1856 }
    1857 
    1858 void GCNDisasmUtils::decodeVOP2Encoding(GCNDisassembler& dasm, size_t codePos,
    1859          RelocIter& relocIter, cxuint spacesToAdd, uint16_t arch,
    1860          const GCNInstruction& gcnInsn, uint32_t insnCode, uint32_t literal,
    1861          FloatLitType displayFloatLits)
    1862 {
    1863     FastOutputBuffer& output = dasm.output;
    1864     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    1865     char* bufStart = output.reserve(150);
    1866     char* bufPtr = bufStart;
    1867    
    1868     addSpaces(bufPtr, spacesToAdd);
    1869     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    1870    
    1871     const cxuint src0Field = (insnCode&0x1ff);
    1872     // extra flags are zeroed by default
    1873     VOPExtraWordOut extraFlags = { 0, 0, 0, 0, 0, 0, 0 };
    1874    
    1875     if (isGCN12)
    1876     {
    1877         // return extra flags from SDWA/DPP encoding
    1878         if (src0Field == 0xf9)
    1879             extraFlags = decodeVOPSDWAFlags(literal, arch);
    1880         else if (src0Field == 0xfa)
    1881             extraFlags = decodeVOPDPPFlags(literal);
    1882         else
    1883             extraFlags.src0 = src0Field;
    1884     }
    1885     else
    1886         extraFlags.src0 = src0Field;
    1887    
    1888     if (mode1 != GCN_DS1_SGPR)
    1889         // print DST as SGPR
    1890         decodeGCNVRegOperand(((insnCode>>17)&0xff),
    1891                      (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr);
    1892     else
    1893         decodeGCNOperandNoLit(dasm, ((insnCode>>17)&0xff),
    1894                  (gcnInsn.mode&GCN_REG_DST_64)?2:1, bufPtr, arch);
    1895    
    1896     // add VCC if V_ADD_XXX or other instruction VCC as DST
    1897     if (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC)
    1898         putChars(bufPtr, ", vcc", 5);
    1899     *bufPtr++ = ',';
    1900     *bufPtr++ = ' ';
    1901     // apply sext, negation and abs if supplied
    1902     if (extraFlags.sextSrc0)
    1903         putChars(bufPtr, "sext(", 5);
    1904     if (extraFlags.negSrc0)
    1905         *bufPtr++ = '-';
    1906     if (extraFlags.absSrc0)
    1907         putChars(bufPtr, "abs(", 4);
    1908     output.forward(bufPtr-bufStart);
    1909     // print SRC0
    1910     bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter, extraFlags.src0,
    1911                  (gcnInsn.mode&GCN_REG_SRC0_64)?2:1, arch, literal, displayFloatLits);
    1912     // closing sext and abs
    1913     if (extraFlags.absSrc0)
    1914         *bufPtr++ = ')';
    1915     if (extraFlags.sextSrc0)
    1916         *bufPtr++ = ')';
    1917     if (mode1 == GCN_ARG1_IMM)
    1918     {
    1919         // extra immediate (like V_MADMK_F32)
    1920         *bufPtr++ = ',';
    1921         *bufPtr++ = ' ';
    1922         output.forward(bufPtr-bufStart);
    1923         printLiteral(dasm, codePos, relocIter, literal, displayFloatLits, false);
    1924         bufStart = bufPtr = output.reserve(100);
    1925     }
    1926     *bufPtr++ = ',';
    1927     *bufPtr++ = ' ';
    1928     // apply sext, negation and abs if supplied
    1929     if (extraFlags.sextSrc1)
    1930         putChars(bufPtr, "sext(", 5);
    1931    
    1932     if (extraFlags.negSrc1)
    1933         *bufPtr++ = '-';
    1934     if (extraFlags.absSrc1)
    1935         putChars(bufPtr, "abs(", 4);
    1936     // print SRC0
    1937     if (mode1 == GCN_DS1_SGPR || mode1 == GCN_SRC1_SGPR)
    1938     {
    1939         output.forward(bufPtr-bufStart);
    1940         bufStart = bufPtr = decodeGCNOperand(dasm, codePos, relocIter,
    1941                  ((insnCode>>9)&0xff), (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, arch);
    1942     }
    1943     else
    1944         decodeGCNOperandNoLit(dasm, ((insnCode>>9)&0xff) +
    1945                 (extraFlags.scalarSrc1 ? 0 : 256),
    1946                 (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr, arch);
    1947     // closing sext and abs
    1948     if (extraFlags.absSrc1)
    1949         *bufPtr++ = ')';
    1950     if (extraFlags.sextSrc1)
    1951         *bufPtr++ = ')';
    1952     if (mode1 == GCN_ARG2_IMM)
    1953     {
    1954         // extra immediate (like V_MADAK_F32)
    1955         *bufPtr++ = ',';
    1956         *bufPtr++ = ' ';
    1957         output.forward(bufPtr-bufStart);
    1958         printLiteral(dasm, codePos, relocIter, literal, displayFloatLits, false);
    1959     }
    1960     else if (mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC)
    1961     {
    1962         // VCC like in V_CNDMASK_B32 or V_SUBB_B32
    1963         putChars(bufPtr, ", vcc", 5);
    1964         output.forward(bufPtr-bufStart);
    1965     }
    1966     else
    1967         output.forward(bufPtr-bufStart);
    1968     if (isGCN12)
    1969     {
    1970         // print extra SDWA/DPP modifiers
    1971         if (src0Field == 0xf9)
    1972             decodeVOPSDWA(output, arch, literal, true, true);
    1973         else if (src0Field == 0xfa)
    1974             decodeVOPDPP(output, literal, true, true);
    1975     }
    1976 }
    1977 
    1978 // VINTRP param names
    1979 static const char* vintrpParamsTbl[] =
    1980 { "p10", "p20", "p0" };
    1981 
    1982 static void decodeVINTRPParam(uint16_t p, char*& bufPtr)
    1983 {
    1984     if (p >= 3)
    1985     {
    1986         putChars(bufPtr, "invalid_", 8);
    1987         bufPtr += itocstrCStyle(p, bufPtr, 8);
    1988     }
    1989     else
    1990         putChars(bufPtr, vintrpParamsTbl[p], ::strlen(vintrpParamsTbl[p]));
    1991 }
    1992 
    1993 void GCNDisasmUtils::decodeVOP3Encoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    1994          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    1995          uint32_t insnCode2, FloatLitType displayFloatLits)
    1996 {
    1997     FastOutputBuffer& output = dasm.output;
    1998     char* bufStart = output.reserve(170);
    1999     char* bufPtr = bufStart;
    2000     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    2001     const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
    2002     const cxuint opcode = (isGCN12) ? ((insnCode>>16)&0x3ff) : ((insnCode>>17)&0x1ff);
    2003    
    2004     const cxuint vdst = insnCode&0xff;
    2005     const cxuint vsrc0 = insnCode2&0x1ff;
    2006     const cxuint vsrc1 = (insnCode2>>9)&0x1ff;
    2007     const cxuint vsrc2 = (insnCode2>>18)&0x1ff;
    2008     const cxuint sdst = (insnCode>>8)&0x7f;
    2009     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    2010     const uint16_t vop3Mode = (gcnInsn.mode&GCN_VOP3_MASK2);
    2011    
    2012     bool vdstUsed = false;
    2013     bool vsrc0Used = false;
    2014     bool vsrc1Used = false;
    2015     bool vsrc2Used = false;
    2016     bool vsrc2CC = false;
    2017     cxuint absFlags = 0;
    2018     cxuint negFlags = 0;
    2019    
    2020     if (gcnInsn.encoding == GCNENC_VOP3A && vop3Mode != GCN_VOP3_VOP3P)
    2021         absFlags = (insnCode>>8)&7;
    2022     // get negation flags from insnCode (VOP3P)
    2023     if (vop3Mode != GCN_VOP3_VOP3P)
    2024         negFlags = (insnCode2>>29)&7;
    2025    
    2026     const bool is128Ops = (gcnInsn.mode&0x7000)==GCN_VOP3_DS2_128;
    2027    
    2028     if (mode1 != GCN_VOP_ARG_NONE)
    2029     {
    2030         addSpaces(bufPtr, spacesToAdd);
    2031        
    2032         if (opcode < 256 || (gcnInsn.mode&GCN_VOP3_DST_SGPR)!=0)
    2033             /* if compares (print DST as SDST) */
    2034             decodeGCNOperandNoLit(dasm, vdst, ((gcnInsn.mode&GCN_VOP3_DST_SGPR)==0)?2:1,
    2035                               bufPtr, arch);
    2036         else /* regular instruction */
    2037             // for V_MQSAD_U32 SRC2 is 128-bit
    2038             decodeGCNVRegOperand(vdst, (is128Ops) ? 4 :
    2039                                  ((gcnInsn.mode&GCN_REG_DST_64)?2:1), bufPtr);
    2040        
    2041         if (gcnInsn.encoding == GCNENC_VOP3B &&
    2042             (mode1 == GCN_DS2_VCC || mode1 == GCN_DST_VCC || mode1 == GCN_DST_VCC_VSRC2 ||
    2043              mode1 == GCN_S0EQS12)) /* VOP3b */
    2044         {
    2045             // print SDST operand (VOP3B)
    2046             *bufPtr++ = ',';
    2047             *bufPtr++ = ' ';
    2048             decodeGCNOperandNoLit(dasm, ((insnCode>>8)&0x7f), 2, bufPtr, arch);
    2049         }
    2050         *bufPtr++ = ',';
    2051         *bufPtr++ = ' ';
    2052         if (vop3Mode != GCN_VOP3_VINTRP)
    2053         {
    2054             // print negation or abs if supplied
    2055             if (negFlags & 1)
    2056                 *bufPtr++ = '-';
    2057             if (absFlags & 1)
    2058                 putChars(bufPtr, "abs(", 4);
    2059             // print VSRC0
    2060             decodeGCNOperandNoLit(dasm, vsrc0, (gcnInsn.mode&GCN_REG_SRC0_64)?2:1,
    2061                                    bufPtr, arch, displayFloatLits);
    2062             // closing abs
    2063             if (absFlags & 1)
    2064                 *bufPtr++ = ')';
    2065             vsrc0Used = true;
    2066         }
    2067        
    2068         if (vop3Mode == GCN_VOP3_VINTRP)
    2069         {
    2070             // print negation or abs if supplied
    2071             if (negFlags & 2)
    2072                 *bufPtr++ = '-';
    2073             if (absFlags & 2)
    2074                 putChars(bufPtr, "abs(", 4);
    2075             if (mode1 == GCN_P0_P10_P20)
    2076                 // VINTRP param
    2077                 decodeVINTRPParam(vsrc1, bufPtr);
    2078             else
    2079                 // print VSRC1
    2080                 decodeGCNOperandNoLit(dasm, vsrc1, 1, bufPtr, arch, displayFloatLits);
    2081             if (absFlags & 2)
    2082                 *bufPtr++ = ')';
    2083             // print VINTRP attr
    2084             putChars(bufPtr, ", attr", 6);
    2085             const cxuint attr = vsrc0&63;
    2086             putByteToBuf(attr, bufPtr);
    2087             *bufPtr++ = '.';
    2088             *bufPtr++ = "xyzw"[((vsrc0>>6)&3)]; // attrchannel
    2089            
    2090             if ((gcnInsn.mode & GCN_VOP3_MASK3) == GCN_VINTRP_SRC2)
    2091             {
    2092                 *bufPtr++ = ',';
    2093                 *bufPtr++ = ' ';
    2094                 // print abs and negation for VSRC2
    2095                 if (negFlags & 4)
    2096                     *bufPtr++ = '-';
    2097                 if (absFlags & 4)
    2098                     putChars(bufPtr, "abs(", 4);
    2099                 // print VSRC2
    2100                 decodeGCNOperandNoLit(dasm, vsrc2, 1, bufPtr, arch, displayFloatLits);
    2101                 if (absFlags & 4)
    2102                     *bufPtr++ = ')';
    2103                 vsrc2Used = true;
    2104             }
    2105            
    2106             if (vsrc0 & 0x100)
    2107                 putChars(bufPtr, " high", 5);
    2108             vsrc0Used = true;
    2109             vsrc1Used = true;
    2110         }
    2111         else if (mode1 != GCN_SRC12_NONE)
    2112         {
    2113             *bufPtr++ = ',';
    2114             *bufPtr++ = ' ';
    2115             // print abs and negation for VSRC1
    2116             if (negFlags & 2)
    2117                 *bufPtr++ = '-';
    2118             if (absFlags & 2)
    2119                 putChars(bufPtr, "abs(", 4);
    2120             // print VSRC1
    2121             decodeGCNOperandNoLit(dasm, vsrc1, (gcnInsn.mode&GCN_REG_SRC1_64)?2:1,
    2122                       bufPtr, arch, displayFloatLits);
    2123             if (absFlags & 2)
    2124                 *bufPtr++ = ')';
    2125             /* GCN_DST_VCC - only sdst is used, no vsrc2 */
    2126             if (mode1 != GCN_SRC2_NONE && mode1 != GCN_DST_VCC && opcode >= 256)
    2127             {
    2128                 *bufPtr++ = ',';
    2129                 *bufPtr++ = ' ';
    2130                
    2131                 if (mode1 == GCN_DS2_VCC || mode1 == GCN_SRC2_VCC)
    2132                 {
    2133                     decodeGCNOperandNoLit(dasm, vsrc2, 2, bufPtr, arch);
    2134                     vsrc2CC = true;
    2135                 }
    2136                 else
    2137                 {
    2138                     // print abs and negation for VSRC2
    2139                     if (negFlags & 4)
    2140                         *bufPtr++ = '-';
    2141                     if (absFlags & 4)
    2142                         putChars(bufPtr, "abs(", 4);
    2143                     // for V_MQSAD_U32 SRC2 is 128-bit
    2144                     // print VSRC2
    2145                     decodeGCNOperandNoLit(dasm, vsrc2, is128Ops ? 4 :
    2146                                 (gcnInsn.mode&GCN_REG_SRC2_64)?2:1,
    2147                                  bufPtr, arch, displayFloatLits);
    2148                     if (absFlags & 4)
    2149                         *bufPtr++ = ')';
    2150                 }
    2151                 vsrc2Used = true;
    2152             }
    2153             vsrc1Used = true;
    2154         }
    2155        
    2156         vdstUsed = true;
    2157     }
    2158     else
    2159         addSpaces(bufPtr, spacesToAdd-1);
    2160    
    2161     uint32_t opselBaseMask = 0;
    2162     uint32_t opselMask = 1;
    2163     uint32_t opsel = 0;
    2164     if (isGCN14 && gcnInsn.encoding != GCNENC_VOP3B)
    2165     {
    2166         opsel = (insnCode >> 11) & 15;
    2167         // print OPSEL
    2168         const bool opsel2Bit = (vop3Mode!=GCN_VOP3_VOP3P && vsrc1Used) ||
    2169             (vop3Mode==GCN_VOP3_VOP3P && vsrc2Used);
    2170         const bool opsel3Bit = (vsrc2Used && vop3Mode!=GCN_VOP3_VOP3P);
    2171         if (vop3Mode!=GCN_VOP3_VOP3P)
    2172         {
    2173             opselMask |= (opsel2Bit?2:0) | (opsel3Bit?4:0) | 8;
    2174             opselBaseMask = (15U<<11);
    2175         }
    2176         else // VOP3P
    2177         {
    2178             opselMask |= (opsel2Bit?6:2);
    2179             opselBaseMask = (7U<<11);
    2180         }
    2181        
    2182         if ((insnCode & (opselMask<<11)) != 0 &&
    2183             ((insnCode & opselBaseMask) & ~(opselMask<<11)) == 0)
    2184         {
    2185             putChars(bufPtr, " op_sel:[", 9);
    2186             *bufPtr++ = (insnCode&0x800) ? '1' : '0';
    2187             *bufPtr++ = ',';
    2188             if (vop3Mode==GCN_VOP3_VOP3P || vsrc1Used)
    2189                 *bufPtr++ = (insnCode&0x1000) ? '1' : '0';
    2190             else
    2191                 // last bit 14-bit dest (for one operand instr)
    2192                 *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
    2193             // print next opsel if next operand is present
    2194             // for VOP3P: VSRC2, non VOP3P - VSRC1
    2195             if (vop3Mode!=GCN_VOP3_VOP3P && vsrc1Used)
    2196             {
    2197                 *bufPtr++ = ',';
    2198                 if (vsrc2Used)
    2199                     *bufPtr++ = (insnCode&0x2000) ? '1' : '0';
    2200                 else
    2201                     // last bit 14-bit dest (no third source operand)
    2202                     *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
    2203             }
    2204             else if (vop3Mode==GCN_VOP3_VOP3P && vsrc2Used)
    2205             {
    2206                 *bufPtr++ = ',';
    2207                 *bufPtr++ = (insnCode&0x2000) ? '1' : '0';
    2208             }
    2209             // only for VOP3P and VSRC2
    2210             if (vsrc2Used && vop3Mode!=GCN_VOP3_VOP3P)
    2211             {
    2212                 *bufPtr++ = ',';
    2213                 *bufPtr++ = (insnCode&0x4000) ? '1' : '0';
    2214             }
    2215             *bufPtr++ = ']';
    2216         }
    2217     }
    2218    
    2219     // fi VOP3P encoding
    2220     if (vop3Mode==GCN_VOP3_VOP3P)
    2221     {
    2222         // print OP_SEL_HI modifier
    2223         cxuint opselHi = ((insnCode2 >> 27) & 3) | (vsrc2Used ? ((insnCode>>12)&4) : 0);
    2224         if (opselHi != 3+(vsrc2Used?4:0))
    2225         {
    2226             putChars(bufPtr, " op_sel_hi:[", 12);
    2227             *bufPtr++ = (insnCode2 & (1U<<27)) ? '1' : '0';
    2228             *bufPtr++ = ',';
    2229             *bufPtr++ = (insnCode2 & (1U<<28)) ? '1' : '0';
    2230             if (vsrc2Used)
    2231             {
    2232                 *bufPtr++ = ',';
    2233                 *bufPtr++ = (insnCode& 0x4000) ? '1' : '0';
    2234             }
    2235             *bufPtr++ = ']';
    2236         }
    2237         // print NEG_LO modifier
    2238         if ((insnCode2&((3+(vsrc2Used?4:0))<<29)) != 0)
    2239         {
    2240             putChars(bufPtr, " neg_lo:[", 9);
    2241             *bufPtr++ = (insnCode2 & (1U<<29)) ? '1' : '0';
    2242             *bufPtr++ = ',';
    2243             *bufPtr++ = (insnCode2 & (1U<<30)) ? '1' : '0';
    2244             if (vsrc2Used)
    2245             {
    2246                 *bufPtr++ = ',';
    2247                 *bufPtr++ = (insnCode2 & (1U<<31)) ? '1' : '0';
    2248             }
    2249             *bufPtr++ = ']';
    2250         }
    2251         // print NEG_HI modifier
    2252         if ((insnCode & ((3+(vsrc2Used?4:0))<<8)) != 0)
    2253         {
    2254             putChars(bufPtr, " neg_hi:[", 9);
    2255             *bufPtr++ = (insnCode & (1U<<8)) ? '1' : '0';
    2256             *bufPtr++ = ',';
    2257             *bufPtr++ = (insnCode & (1U<<9)) ? '1' : '0';
    2258             if (vsrc2Used)
    2259             {
    2260                 *bufPtr++ = ',';
    2261                 *bufPtr++ = (insnCode & (1U<<10)) ? '1' : '0';
    2262             }
    2263             *bufPtr++ = ']';
    2264         }
    2265     }
    2266    
    2267     const cxuint omod = (insnCode2>>27)&3;
    2268     if (vop3Mode != GCN_VOP3_VOP3P && omod != 0)
    2269     {
    2270         const char* omodStr = (omod==3)?" div:2":(omod==2)?" mul:4":" mul:2";
    2271         putChars(bufPtr, omodStr, 6);
    2272     }
    2273    
    2274     const bool clamp = (!isGCN12 && gcnInsn.encoding == GCNENC_VOP3A &&
    2275             (insnCode&0x800) != 0) || (isGCN12 && (insnCode&0x8000) != 0);
    2276     if (clamp)
    2277         putChars(bufPtr, " clamp", 6);
    2278    
    2279     /* print unused values of parts if not values are not default */
    2280     if (!vdstUsed && vdst != 0)
    2281     {
    2282         putChars(bufPtr, " dst=", 5);
    2283         bufPtr += itocstrCStyle(vdst, bufPtr, 6, 16);
    2284     }
    2285    
    2286     if (!vsrc0Used)
    2287     {
    2288         if (vsrc0 != 0)
    2289         {
    2290             putChars(bufPtr, " src0=", 6);
    2291             bufPtr += itocstrCStyle(vsrc0, bufPtr, 6, 16);
    2292         }
    2293         if (absFlags & 1)
    2294             putChars(bufPtr, " abs0", 5);
    2295         if ((insnCode2 & (1U<<29)) != 0)
    2296             putChars(bufPtr, " neg0", 5);
    2297     }
    2298     if (!vsrc1Used)
    2299     {
    2300         if (vsrc1 != 0)
    2301         {
    2302             putChars(bufPtr, " vsrc1=", 7);
    2303             bufPtr += itocstrCStyle(vsrc1, bufPtr, 6, 16);
    2304         }
    2305         if (absFlags & 2)
    2306             putChars(bufPtr, " abs1", 5);
    2307         if ((insnCode2 & (1U<<30)) != 0)
    2308             putChars(bufPtr, " neg1", 5);
    2309     }
    2310     if (!vsrc2Used)
    2311     {
    2312         if (vsrc2 != 0)
    2313         {
    2314             putChars(bufPtr, " vsrc2=", 7);
    2315             bufPtr += itocstrCStyle(vsrc2, bufPtr, 6, 16);
    2316         }
    2317         if (absFlags & 4)
    2318             putChars(bufPtr, " abs2", 5);
    2319         if ((insnCode2 & (1U<<31)) != 0)
    2320             putChars(bufPtr, " neg2", 5);
    2321     }
    2322    
    2323     // unused op_sel field
    2324     if (isGCN14 && ((insnCode & opselBaseMask) & ~(opselMask<<11)) != 0 &&
    2325         gcnInsn.encoding != GCNENC_VOP3B)
    2326     {
    2327         putChars(bufPtr, " op_sel=", 8);
    2328         bufPtr += itocstrCStyle((insnCode>>11)&15, bufPtr, 6, 16);
    2329     }
    2330    
    2331     const cxuint usedMask = 7 & ~(vsrc2CC?4:0);
    2332     /* check whether instruction is this same like VOP2/VOP1/VOPC */
    2333     bool isVOP1Word = false; // if can be write in single VOP dword
    2334     if (vop3Mode == GCN_VOP3_VINTRP)
    2335     {
    2336         if (mode1 != GCN_NEW_OPCODE) /* check clamp and abs flags */
    2337             isVOP1Word = !((insnCode&(7<<8)) != 0 || (insnCode2&(7<<29)) != 0 ||
    2338                     clamp || omod!=0 || ((vsrc1 < 256 && mode1!=GCN_P0_P10_P20) ||
    2339                     (mode1==GCN_P0_P10_P20 && vsrc1 >= 256)) ||
    2340                     vsrc0 >= 256 || vsrc2 != 0);
    2341     }
    2342     else if (mode1 != GCN_ARG1_IMM && mode1 != GCN_ARG2_IMM)
    2343     {
    2344         const bool reqForVOP1Word = omod==0 && ((insnCode2&(usedMask<<29)) == 0);
    2345         if (gcnInsn.encoding != GCNENC_VOP3B)
    2346         {
    2347             /* for VOPC */
    2348             if (opcode < 256 && vdst == 106 /* vcc */ && vsrc1 >= 256 && vsrc2 == 0)
    2349                 isVOP1Word = true;
    2350             /* for VOP1 */
    2351             else if (vop3Mode == GCN_VOP3_VOP1 && vsrc1 == 0 && vsrc2 == 0)
    2352                 isVOP1Word = true;
    2353             /* for VOP2 */
    2354             else if (vop3Mode == GCN_VOP3_VOP2 && ((!vsrc1Used && vsrc1 == 0) ||
    2355                 /* distinguish for v_read/writelane and other vop2 encoded as vop3 */
    2356                 (((gcnInsn.mode&GCN_VOP3_SRC1_SGPR)==0) && vsrc1 >= 256) ||
    2357                 (((gcnInsn.mode&GCN_VOP3_SRC1_SGPR)!=0) && vsrc1 < 256)) &&
    2358                 ((mode1 != GCN_SRC2_VCC && vsrc2 == 0) ||
    2359                 (vsrc2 == 106 && mode1 == GCN_SRC2_VCC)))
    2360                 isVOP1Word = true;
    2361             /* check clamp and abs and neg flags */
    2362             if ((insnCode&(usedMask<<8)) != 0 || (insnCode2&(usedMask<<29)) != 0 || clamp)
    2363                 isVOP1Word = false;
    2364         }
    2365         /* for VOP2 encoded as VOP3b (v_addc....) */
    2366         else if (gcnInsn.encoding == GCNENC_VOP3B && vop3Mode == GCN_VOP3_VOP2 &&
    2367                 vsrc1 >= 256 && sdst == 106 /* vcc */ &&
    2368                 ((vsrc2 == 106 && mode1 == GCN_DS2_VCC) ||
    2369                     (vsrc2 == 0 && mode1 != GCN_DS2_VCC))) /* VOP3b */
    2370             isVOP1Word = true;
    2371        
    2372         if (isVOP1Word && !reqForVOP1Word)
    2373             isVOP1Word = false;
    2374         if (opsel != 0)
    2375             isVOP1Word = false;
    2376     }
    2377     else // force for v_madmk_f32 and v_madak_f32
    2378         isVOP1Word = true;
    2379    
    2380     if (isVOP1Word) // add vop3 for distinguishing encoding
    2381         putChars(bufPtr, " vop3", 5);
    2382    
    2383     output.forward(bufPtr-bufStart);
    2384 }
    2385 
    2386 void GCNDisasmUtils::decodeVINTRPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    2387           uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode)
    2388 {
    2389     FastOutputBuffer& output = dasm.output;
    2390     char* bufStart = output.reserve(90);
    2391     char* bufPtr = bufStart;
    2392     addSpaces(bufPtr, spacesToAdd);
    2393     // print DST operand
    2394     decodeGCNVRegOperand((insnCode>>18)&0xff, 1, bufPtr);
    2395     *bufPtr++ = ',';
    2396     *bufPtr++ = ' ';
    2397     if ((gcnInsn.mode & GCN_MASK1) == GCN_P0_P10_P20)
    2398         // print VINTRP param
    2399         decodeVINTRPParam(insnCode&0xff, bufPtr);
    2400     else
    2401         // or VSRC0 operand
    2402         decodeGCNVRegOperand(insnCode&0xff, 1, bufPtr);
    2403     putChars(bufPtr, ", attr", 6);
    2404     const cxuint attr = (insnCode>>10)&63;
    2405     putByteToBuf(attr, bufPtr);
    2406     *bufPtr++ = '.';
    2407     *bufPtr++ = "xyzw"[((insnCode>>8)&3)]; // attrchannel
    2408     output.forward(bufPtr-bufStart);
    2409 }
    2410 
    2411 void GCNDisasmUtils::decodeDSEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    2412           uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    2413           uint32_t insnCode2)
    2414 {
    2415     FastOutputBuffer& output = dasm.output;
    2416     char* bufStart = output.reserve(105);
    2417     char* bufPtr = bufStart;
    2418     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    2419     addSpaces(bufPtr, spacesToAdd);
    2420     bool vdstUsed = false;
    2421     bool vaddrUsed = false;
    2422     bool vdata0Used = false;
    2423     bool vdata1Used = false;
    2424     const cxuint vaddr = insnCode2&0xff;
    2425     const cxuint vdata0 = (insnCode2>>8)&0xff;
    2426     const cxuint vdata1 = (insnCode2>>16)&0xff;
    2427     const cxuint vdst = insnCode2>>24;
    2428    
    2429     if (((gcnInsn.mode & GCN_ADDR_SRC) != 0 || (gcnInsn.mode & GCN_ONLYDST) != 0) &&
    2430             (gcnInsn.mode & GCN_ONLY_SRC) == 0)
    2431     {
    2432         /* vdst is dst */
    2433         cxuint regsNum = (gcnInsn.mode&GCN_REG_DST_64)?2:1;
    2434         if ((gcnInsn.mode&GCN_DS_96) != 0)
    2435             regsNum = 3;
    2436         if ((gcnInsn.mode&GCN_DS_128) != 0 || (gcnInsn.mode&GCN_DST128) != 0)
    2437             regsNum = 4;
    2438         // print VDST
    2439         decodeGCNVRegOperand(vdst, regsNum, bufPtr);
    2440         vdstUsed = true;
    2441     }
    2442     if ((gcnInsn.mode & GCN_ONLYDST) == 0 && (gcnInsn.mode & GCN_ONLY_SRC) == 0)
    2443     {
    2444         /// print VADDR
    2445         if (vdstUsed)
    2446         {
    2447             *bufPtr++ = ',';
    2448             *bufPtr++ = ' ';
    2449         }
    2450         decodeGCNVRegOperand(vaddr, 1, bufPtr);
    2451         vaddrUsed = true;
    2452     }
    2453    
    2454     const uint16_t srcMode = (gcnInsn.mode & GCN_SRCS_MASK);
    2455    
    2456     if ((gcnInsn.mode & GCN_ONLYDST) == 0 &&
    2457         (gcnInsn.mode & (GCN_ADDR_DST|GCN_ADDR_SRC)) != 0 && srcMode != GCN_NOSRC)
    2458     {
    2459         /* print two vdata */
    2460         if (vaddrUsed || vdstUsed)
    2461         {
    2462             // comma after previous argument (VDST, VADDR)
    2463             *bufPtr++ = ',';
    2464             *bufPtr++ = ' ';
    2465         }
    2466         // determine number of register for VDATA0
    2467         cxuint regsNum = (gcnInsn.mode&GCN_REG_SRC0_64)?2:1;
    2468         if ((gcnInsn.mode&GCN_DS_96) != 0)
    2469             regsNum = 3;
    2470         if ((gcnInsn.mode&GCN_DS_128) != 0)
    2471             regsNum = 4;
    2472         // print VDATA0
    2473         decodeGCNVRegOperand(vdata0, regsNum, bufPtr);
    2474         vdata0Used = true;
    2475         if (srcMode == GCN_2SRCS)
    2476         {
    2477             *bufPtr++ = ',';
    2478             *bufPtr++ = ' ';
    2479             // print VDATA1
    2480             decodeGCNVRegOperand(vdata1, (gcnInsn.mode&GCN_REG_SRC1_64)?2:1, bufPtr);
    2481             vdata1Used = true;
    2482         }
    2483     }
    2484    
    2485     const cxuint offset = (insnCode&0xffff);
    2486     // printing offsets (one 16-bit or two 8-bit)
    2487     if (offset != 0)
    2488     {
    2489         if ((gcnInsn.mode & GCN_2OFFSETS) == 0) /* single offset */
    2490         {
    2491             putChars(bufPtr, " offset:", 8);
    2492             bufPtr += itocstrCStyle(offset, bufPtr, 7, 10);
    2493         }
    2494         else
    2495         {
    2496             // if two 8-bit offsets (if supplied)
    2497             if ((offset&0xff) != 0)
    2498             {
    2499                 putChars(bufPtr, " offset0:", 9);
    2500                 putByteToBuf(offset&0xff, bufPtr);
    2501             }
    2502             if ((offset&0xff00) != 0)
    2503             {
    2504                 putChars(bufPtr, " offset1:", 9);
    2505                 putByteToBuf((offset>>8)&0xff, bufPtr);
    2506             }
    2507         }
    2508     }
    2509    
    2510     if ((!isGCN12 && (insnCode&0x20000)!=0) || (isGCN12 && (insnCode&0x10000)!=0))
    2511         putChars(bufPtr, " gds", 4);
    2512    
    2513     // print value, if some are not used, but values is not default
    2514     if (!vaddrUsed && vaddr != 0)
    2515     {
    2516         putChars(bufPtr, " vaddr=", 7);
    2517         bufPtr += itocstrCStyle(vaddr, bufPtr, 6, 16);
    2518     }
    2519     if (!vdata0Used && vdata0 != 0)
    2520     {
    2521         putChars(bufPtr, " vdata0=", 8);
    2522         bufPtr += itocstrCStyle(vdata0, bufPtr, 6, 16);
    2523     }
    2524     if (!vdata1Used && vdata1 != 0)
    2525     {
    2526         putChars(bufPtr, " vdata1=", 8);
    2527         bufPtr += itocstrCStyle(vdata1, bufPtr, 6, 16);
    2528     }
    2529     if (!vdstUsed && vdst != 0)
    2530     {
    2531         putChars(bufPtr, " vdst=", 6);
    2532         bufPtr += itocstrCStyle(vdst, bufPtr, 6, 16);
    2533     }
    2534     output.forward(bufPtr-bufStart);
    2535 }
    2536 
    2537 // print DATA FORMAT name table
    2538 static const char* mtbufDFMTTable[] =
    2539 {
    2540     "invalid", "8", "16", "8_8", "32", "16_16", "10_11_11", "11_11_10",
    2541     "10_10_10_2", "2_10_10_10", "8_8_8_8", "32_32", "16_16_16_16", "32_32_32",
    2542     "32_32_32_32", "reserved"
    2543 };
    2544 
    2545 // print NUMBER FORMAT name table
    2546 static const char* mtbufNFMTTable[] =
    2547 {
    2548     "unorm", "snorm", "uscaled", "sscaled",
    2549     "uint", "sint", "snorm_ogl", "float"
    2550 };
    2551 
    2552 void GCNDisasmUtils::decodeMUBUFEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    2553           uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    2554           uint32_t insnCode2)
    2555 {
    2556     FastOutputBuffer& output = dasm.output;
    2557     char* bufStart = output.reserve(170);
    2558     char* bufPtr = bufStart;
    2559     const bool isGCN12 = ((arch&ARCH_GCN_1_2_4)!=0);
    2560     const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
    2561     const cxuint vaddr = insnCode2&0xff;
    2562     const cxuint vdata = (insnCode2>>8)&0xff;
    2563     const cxuint srsrc = (insnCode2>>16)&0x1f;
    2564     const cxuint soffset = insnCode2>>24;
    2565     const uint16_t mode1 = (gcnInsn.mode & GCN_MASK1);
    2566     if (mode1 != GCN_ARG_NONE)
    2567     {
    2568         addSpaces(bufPtr, spacesToAdd);
    2569         if (mode1 != GCN_MUBUF_NOVAD)
    2570         {
    2571             // determine number of regs in VDATA
    2572             cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
    2573             if ((gcnInsn.mode & GCN_MUBUF_D16)!=0 && isGCN14)
    2574                 // 16-bit values packed into half of number of registers
    2575                 dregsNum = (dregsNum+1)>>1;
    2576             if (insnCode2 & 0x800000U)
    2577                 dregsNum++; // tfe
    2578             // print VDATA
    2579             decodeGCNVRegOperand(vdata, dregsNum, bufPtr);
    2580             *bufPtr++ = ',';
    2581             *bufPtr++ = ' ';
    2582             // determine number of vaddr registers
    2583             /* for addr32 - idxen+offen or 1, for addr64 - 2 (idxen and offen is illegal) */
    2584             const cxuint aregsNum = ((insnCode & 0x3000U)==0x3000U ||
    2585                     /* addr64 only for older GCN than 1.2 */
    2586                     (!isGCN12 && (insnCode & 0x8000U)))? 2 : 1;
    2587             // print VADDR
    2588             decodeGCNVRegOperand(vaddr, aregsNum, bufPtr);
    2589             *bufPtr++ = ',';
    2590             *bufPtr++ = ' ';
    2591         }
    2592         // print SRSRC
    2593         decodeGCNOperandNoLit(dasm, srsrc<<2, 4, bufPtr, arch);
    2594         *bufPtr++ = ',';
    2595         *bufPtr++ = ' ';
    2596         // print SOFFSET
    2597         decodeGCNOperandNoLit(dasm, soffset, 1, bufPtr, arch);
    2598     }
    2599     else
    2600         addSpaces(bufPtr, spacesToAdd-1);
    2601    
    2602     // print modifiers: (offen and idxen, glc)
    2603     if (insnCode & 0x1000U)
    2604         putChars(bufPtr, " offen", 6);
    2605     if (insnCode & 0x2000U)
    2606         putChars(bufPtr, " idxen", 6);
    2607     const cxuint offset = insnCode&0xfff;
    2608     if (offset != 0)
    2609     {
    2610         putChars(bufPtr, " offset:", 8);
    2611         bufPtr += itocstrCStyle(offset, bufPtr, 7, 10);
    2612     }
    2613     if (insnCode & 0x4000U)
    2614         putChars(bufPtr, " glc", 4);
    2615    
    2616     // print SLD if supplied
    2617     if (((!isGCN12 || gcnInsn.encoding==GCNENC_MTBUF) && (insnCode2 & 0x400000U)!=0) ||
    2618         ((isGCN12 && gcnInsn.encoding!=GCNENC_MTBUF) && (insnCode & 0x20000)!=0))
    2619         putChars(bufPtr, " slc", 4);
    2620    
    2621     if (!isGCN12 && (insnCode & 0x8000U)!=0)
    2622         putChars(bufPtr, " addr64", 7);
    2623     if (gcnInsn.encoding!=GCNENC_MTBUF && (insnCode & 0x10000U) != 0)
    2624         putChars(bufPtr, " lds", 4);
    2625     if (insnCode2 & 0x800000U)
    2626         putChars(bufPtr, " tfe", 4);
    2627     // routine to decode MTBUF format (include default values)
    2628     if (gcnInsn.encoding==GCNENC_MTBUF)
    2629     {
    2630         const cxuint dfmt = (insnCode>>19)&15;
    2631         const cxuint nfmt = (insnCode>>23)&7;
    2632         if (dfmt!=1 || nfmt!=0)
    2633         {
    2634             // in shortened form: format:[DFMT, NFMT]
    2635             putChars(bufPtr, " format:[", 9);
    2636             if (dfmt!=1)
    2637             {
    2638                 // print DATA_FORMAT if not default
    2639                 const char* dfmtStr = mtbufDFMTTable[dfmt];
    2640                 putChars(bufPtr, dfmtStr, ::strlen(dfmtStr));
    2641             }
    2642             if (dfmt!=1 && nfmt!=0)
    2643                 *bufPtr++ = ',';
    2644             if (nfmt!=0)
    2645             {
    2646                 // print NUMBER_FORMAT if not default
    2647                 const char* nfmtStr = mtbufNFMTTable[nfmt];
    2648                 putChars(bufPtr, nfmtStr, ::strlen(nfmtStr));
    2649             }
    2650             *bufPtr++ = ']';
    2651         }
    2652     }
    2653     // print value, if some are not used, but values is not default
    2654     if (mode1 == GCN_ARG_NONE || mode1 == GCN_MUBUF_NOVAD)
    2655     {
    2656         if (vaddr != 0)
    2657         {
    2658             putChars(bufPtr, " vaddr=", 7);
    2659             bufPtr += itocstrCStyle(vaddr, bufPtr, 6, 16);
    2660         }
    2661         if (vdata != 0)
    2662         {
    2663             putChars(bufPtr, " vdata=", 7);
    2664             bufPtr += itocstrCStyle(vdata, bufPtr, 6, 16);
    2665         }
    2666     }
    2667     // also SRSRC and SOFFSET if no argument in instruction
    2668     if (mode1 == GCN_ARG_NONE)
    2669     {
    2670         if (srsrc != 0)
    2671         {
    2672             putChars(bufPtr, " srsrc=", 7);
    2673             bufPtr += itocstrCStyle(srsrc, bufPtr, 6, 16);
    2674         }
    2675         if (soffset != 0)
    2676         {
    2677             putChars(bufPtr, " soffset=", 9);
    2678             bufPtr += itocstrCStyle(soffset, bufPtr, 6, 16);
    2679         }
    2680     }
    2681     output.forward(bufPtr-bufStart);
    2682 }
    2683 
    2684 void GCNDisasmUtils::decodeMIMGEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    2685          uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    2686          uint32_t insnCode2)
    2687 {
    2688     const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
    2689     FastOutputBuffer& output = dasm.output;
    2690     char* bufStart = output.reserve(170);
    2691     char* bufPtr = bufStart;
    2692     addSpaces(bufPtr, spacesToAdd);
    2693    
    2694     const cxuint dmask = (insnCode>>8)&15;
    2695     cxuint dregsNum = 4;
    2696     // determine register number for VDATA
    2697     if ((gcnInsn.mode & GCN_MIMG_VDATA4) == 0)
    2698         dregsNum = ((dmask & 1)?1:0) + ((dmask & 2)?1:0) + ((dmask & 4)?1:0) +
    2699                 ((dmask & 8)?1:0);
    2700    
    2701     dregsNum = (dregsNum == 0) ? 1 : dregsNum;
    2702     if (insnCode & 0x10000)
    2703         dregsNum++; // tfe
    2704    
    2705     // print VDATA
    2706     decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
    2707     *bufPtr++ = ',';
    2708     *bufPtr++ = ' ';
    2709     // print VADDR
    2710     decodeGCNVRegOperand(insnCode2&0xff,
    2711                  std::max(4, (gcnInsn.mode&GCN_MIMG_VA_MASK)+1), bufPtr);
    2712     *bufPtr++ = ',';
    2713     *bufPtr++ = ' ';
    2714     // print SRSRC
    2715     decodeGCNOperandNoLit(dasm, ((insnCode2>>14)&0x7c),
    2716                 (((insnCode & 0x8000)!=0) && !isGCN14) ? 4: 8, bufPtr, arch);
    2717    
    2718     const cxuint ssamp = (insnCode2>>21)&0x1f;
    2719     if ((gcnInsn.mode & GCN_MIMG_SAMPLE) != 0)
    2720     {
    2721         *bufPtr++ = ',';
    2722         *bufPtr++ = ' ';
    2723         // print SSAMP if supplied
    2724         decodeGCNOperandNoLit(dasm, ssamp<<2, 4, bufPtr, arch);
    2725     }
    2726     if (dmask != 1)
    2727     {
    2728         putChars(bufPtr, " dmask:", 7);
    2729         // print value dmask (0-15)
    2730         if (dmask >= 10)
    2731         {
    2732             *bufPtr++ = '1';
    2733             *bufPtr++ = '0' + dmask - 10;
    2734         }
    2735         else
    2736             *bufPtr++ = '0' + dmask;
    2737     }
    2738    
    2739     // print other modifiers (unorm, glc, slc, ...)
    2740     if (insnCode & 0x1000)
    2741         putChars(bufPtr, " unorm", 6);
    2742     if (insnCode & 0x2000)
    2743         putChars(bufPtr, " glc", 4);
    2744     if (insnCode & 0x2000000)
    2745         putChars(bufPtr, " slc", 4);
    2746     if (insnCode & 0x8000)
    2747     {
    2748         if (!isGCN14)
    2749             putChars(bufPtr, " r128", 5);
    2750         else
    2751             putChars(bufPtr, " a16", 4);
    2752     }
    2753     if (insnCode & 0x10000)
    2754         putChars(bufPtr, " tfe", 4);
    2755     if (insnCode & 0x20000)
    2756         putChars(bufPtr, " lwe", 4);
    2757     if (insnCode & 0x4000)
    2758     {
    2759         // DA modifier
    2760         *bufPtr++ = ' ';
    2761         *bufPtr++ = 'd';
    2762         *bufPtr++ = 'a';
    2763     }
    2764     if ((arch & ARCH_GCN_1_2_4)!=0 && (insnCode2 & (1U<<31)) != 0)
    2765         putChars(bufPtr, " d16", 4);
    2766    
    2767     // print value, if some are not used, but values is not default
    2768     if ((gcnInsn.mode & GCN_MIMG_SAMPLE) == 0 && ssamp != 0)
    2769     {
    2770         putChars(bufPtr, " ssamp=", 7);
    2771         bufPtr += itocstrCStyle(ssamp, bufPtr, 6, 16);
    2772     }
    2773     output.forward(bufPtr-bufStart);
    2774 }
    2775 
    2776 void GCNDisasmUtils::decodeEXPEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    2777             uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    2778             uint32_t insnCode2)
    2779 {
    2780     FastOutputBuffer& output = dasm.output;
    2781     char* bufStart = output.reserve(100);
    2782     char* bufPtr = bufStart;
    2783     addSpaces(bufPtr, spacesToAdd);
    2784     /* export target */
    2785     const cxuint target = (insnCode>>4)&63;
    2786     if (target >= 32)
    2787     {
    2788         // print paramXX
    2789         putChars(bufPtr, "param", 5);
    2790         const cxuint tpar = target-32;
    2791         const cxuint digit2 = tpar/10;
    2792         if (digit2 != 0)
    2793             *bufPtr++ = '0' + digit2;
    2794         *bufPtr++ = '0' + tpar - 10*digit2;
    2795     }
    2796     else if (target >= 12 && target <= 15)
    2797     {
    2798         // print posX
    2799         putChars(bufPtr, "pos0", 4);
    2800         bufPtr[-1] = '0' + target-12;
    2801     }
    2802     else if (target < 8)
    2803     {
    2804         // print mrtX
    2805         putChars(bufPtr, "mrt0", 4);
    2806         bufPtr[-1] = '0' + target;
    2807     }
    2808     else if (target == 8)
    2809         putChars(bufPtr, "mrtz", 4);
    2810     else if (target == 9)
    2811         putChars(bufPtr, "null", 4);
    2812     else
    2813     {
    2814         /* reserved */
    2815         putChars(bufPtr, "ill_", 4);
    2816         const cxuint digit2 = target/10U;
    2817         *bufPtr++ = '0' + digit2;
    2818         *bufPtr++ = '0' + target - 10U*digit2;
    2819     }
    2820    
    2821     /* print vdata registers */
    2822     cxuint vsrcsUsed = 0;
    2823     for (cxuint i = 0; i < 4; i++)
    2824     {
    2825         *bufPtr++ = ',';
    2826         *bufPtr++ = ' ';
    2827         if (insnCode & (1U<<i))
    2828         {
    2829             if ((insnCode&0x400)==0)
    2830             {
    2831                 decodeGCNVRegOperand((insnCode2>>(i<<3))&0xff, 1, bufPtr);
    2832                 vsrcsUsed |= 1<<i;
    2833             }
    2834             else
    2835             {
    2836                 // if compr=1
    2837                 decodeGCNVRegOperand(((i>=2)?(insnCode2>>8):insnCode2)&0xff, 1, bufPtr);
    2838                 vsrcsUsed |= 1U<<(i>>1);
    2839             }
    2840         }
    2841         else
    2842             putChars(bufPtr, "off", 3);
    2843     }
    2844    
    2845     // other modifiers
    2846     if (insnCode&0x800)
    2847         putChars(bufPtr, " done", 5);
    2848     if (insnCode&0x400)
    2849         putChars(bufPtr, " compr", 6);
    2850     if (insnCode&0x1000)
    2851     {
    2852         // VM modifier
    2853         *bufPtr++ = ' ';
    2854         *bufPtr++ = 'v';
    2855         *bufPtr++ = 'm';
    2856     }
    2857    
    2858     // print value, if some are not used, but values is not default
    2859     for (cxuint i = 0; i < 4; i++)
    2860     {
    2861         const cxuint val = (insnCode2>>(i<<3))&0xff;
    2862         if ((vsrcsUsed&(1U<<i))==0 && val!=0)
    2863         {
    2864             putChars(bufPtr, " vsrc0=", 7);
    2865             bufPtr[-2] += i; // number
    2866             bufPtr += itocstrCStyle(val, bufPtr, 6, 16);
    2867         }
    2868     }
    2869     output.forward(bufPtr-bufStart);
    2870 }
    2871 
    2872 // routine to print FLAT address including 'off' for GCN 1.4
    2873 void GCNDisasmUtils::printFLATAddr(cxuint flatMode, char*& bufPtr, uint32_t insnCode2)
    2874 {
    2875     const cxuint vaddr = insnCode2&0xff;
    2876     if (flatMode == 0)
    2877         decodeGCNVRegOperand(vaddr, 2 , bufPtr); // addr
    2878     else if (flatMode == GCN_FLAT_GLOBAL)
    2879         decodeGCNVRegOperand(vaddr,
    2880                 // if off in SADDR, then single VGPR offset
    2881                 ((insnCode2>>16)&0x7f) == 0x7f ? 2 : 1, bufPtr); // addr
    2882     else if (flatMode == GCN_FLAT_SCRATCH)
    2883     {
    2884         if (((insnCode2>>16)&0x7f) == 0x7f)
    2885             decodeGCNVRegOperand(vaddr, 1, bufPtr); // addr
    2886         else // no vaddr
    2887             putChars(bufPtr, "off", 3);
    2888     }
    2889 }
    2890 
    2891 void GCNDisasmUtils::decodeFLATEncoding(GCNDisassembler& dasm, cxuint spacesToAdd,
    2892             uint16_t arch, const GCNInstruction& gcnInsn, uint32_t insnCode,
    2893             uint32_t insnCode2)
    2894 {
    2895     const bool isGCN14 = ((arch&ARCH_RXVEGA)!=0);
    2896     FastOutputBuffer& output = dasm.output;
    2897     char* bufStart = output.reserve(150);
    2898     char* bufPtr = bufStart;
    2899     addSpaces(bufPtr, spacesToAdd);
    2900     bool vdstUsed = false;
    2901     bool vdataUsed = false;
    2902     bool saddrUsed = false;
    2903     const cxuint dregsNum = ((gcnInsn.mode&GCN_DSIZE_MASK)>>GCN_SHIFT2)+1;
    2904     /// cmpswap store only to half of number of data registers
    2905     cxuint dstRegsNum = ((gcnInsn.mode & GCN_CMPSWAP)!=0) ? (dregsNum>>1) :  dregsNum;
    2906     const cxuint flatMode = gcnInsn.mode & GCN_FLAT_MODEMASK;
    2907     // add tfe extra register if needed
    2908     dstRegsNum = (!isGCN14 && (insnCode2 & 0x800000U)) ? dstRegsNum+1 : dstRegsNum;
    2909    
    2910     bool printAddr = false;
    2911     if ((gcnInsn.mode & GCN_FLAT_ADST) == 0)
    2912     {
    2913         vdstUsed = true;
    2914         // print VDST
    2915         decodeGCNVRegOperand(insnCode2>>24, dstRegsNum, bufPtr);
    2916         *bufPtr++ = ',';
    2917         *bufPtr++ = ' ';
    2918         printFLATAddr(flatMode, bufPtr, insnCode2);
    2919         printAddr = true;
    2920     }
    2921     else
    2922     {
    2923         /* two vregs, because 64-bitness stored in PTR32 mode (at runtime) */
    2924         printFLATAddr(flatMode, bufPtr, insnCode2);
    2925         printAddr = true;
    2926         if ((gcnInsn.mode & GCN_FLAT_NODST) == 0)
    2927         {
    2928             vdstUsed = true;
    2929             *bufPtr++ = ',';
    2930             *bufPtr++ = ' ';
    2931             // print VDST
    2932             decodeGCNVRegOperand(insnCode2>>24, dstRegsNum, bufPtr);
    2933         }
    2934     }
    2935    
    2936     if ((gcnInsn.mode & GCN_FLAT_NODATA) == 0) /* print data */
    2937     {
    2938         vdataUsed = true;
    2939         *bufPtr++ = ',';
    2940         *bufPtr++ = ' ';
    2941         // print DATA field
    2942         decodeGCNVRegOperand((insnCode2>>8)&0xff, dregsNum, bufPtr);
    2943     }
    2944    
    2945     if (flatMode != 0 && printAddr)
    2946     {
    2947         // if GLOBAL_ or SCRATCH_
    2948         *bufPtr++ = ',';
    2949         *bufPtr++ = ' ';
    2950         cxuint saddr = (insnCode2>>16)&0x7f;
    2951         if ((saddr&0x7f) != 0x7f)
    2952             // print SADDR (GCN 1.4)
    2953             decodeGCNOperandNoLit(dasm, saddr, flatMode == GCN_FLAT_SCRATCH ? 1 : 2,
    2954                         bufPtr, arch, FLTLIT_NONE);
    2955         else // off
    2956             putChars(bufPtr, "off", 3);
    2957         saddrUsed = true;
    2958     }
    2959    
    2960     // get inst_offset, with sign if FLAT_SCRATCH, FLAT_GLOBAL
    2961     const cxint instOffset = (flatMode != 0 && (insnCode&0x1000) != 0) ?
    2962                 -4096+(insnCode&0xfff) : insnCode&0xfff;
    2963     if (isGCN14 && instOffset != 0)
    2964     {
    2965         putChars(bufPtr, " inst_offset:", 13);
    2966         bufPtr += itocstrCStyle(instOffset, bufPtr, 7, 10);
    2967     }
    2968    
    2969     // print other modifers
    2970     if (isGCN14 && (insnCode & 0x2000U))
    2971         putChars(bufPtr, " lds", 4);
    2972     if (insnCode & 0x10000U)
    2973         putChars(bufPtr, " glc", 4);
    2974     if (insnCode & 0x20000U)
    2975         putChars(bufPtr, " slc", 4);
    2976     if (insnCode2 & 0x800000U)
    2977     {
    2978         if (!isGCN14)
    2979             putChars(bufPtr, " tfe", 4);
    2980         else
    2981             // if GCN 1.4 this bit is NV
    2982             putChars(bufPtr, " nv", 3);
    2983     }
    2984    
    2985     // print value, if some are not used, but values is not default
    2986     if (!vdataUsed && ((insnCode2>>8)&0xff) != 0)
    2987     {
    2988         putChars(bufPtr, " vdata=", 7);
    2989         bufPtr += itocstrCStyle((insnCode2>>8)&0xff, bufPtr, 6, 16);
    2990     }
    2991     if (!vdstUsed && (insnCode2>>24) != 0)
    2992     {
    2993         putChars(bufPtr, " vdst=", 6);
    2994         bufPtr += itocstrCStyle(insnCode2>>24, bufPtr, 6, 16);
    2995     }
    2996     if (flatMode != 0 && !saddrUsed && ((insnCode>>16)&0xff) != 0)
    2997     {
    2998         putChars(bufPtr, " saddr=", 7);
    2999         bufPtr += itocstrCStyle((insnCode2>>16)&0xff, bufPtr, 6, 16);
    3000     }
    3001     output.forward(bufPtr-bufStart);
    3002 }
    3003447
    3004448/* main routine */
Note: See TracChangeset for help on using the changeset viewer.