106c3fb27SDimitry Andric //===-- RISCVInstPrinter.cpp - Convert RISC-V MCInst to asm syntax --------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 906c3fb27SDimitry Andric // This class prints an RISC-V MCInst to a .s file. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "RISCVInstPrinter.h" 14e8d8bef9SDimitry Andric #include "RISCVBaseInfo.h" 15e8d8bef9SDimitry Andric #include "RISCVMCExpr.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 195f757f3fSDimitry Andric #include "llvm/MC/MCInstPrinter.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 210b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 230b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 240b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 250b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h" 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric // Include the auto-generated portion of the assembly writer. 310b57cec5SDimitry Andric #define PRINT_ALIAS_INSTR 320b57cec5SDimitry Andric #include "RISCVGenAsmWriter.inc" 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric static cl::opt<bool> 350b57cec5SDimitry Andric NoAliases("riscv-no-aliases", 360b57cec5SDimitry Andric cl::desc("Disable the emission of assembler pseudo instructions"), 370b57cec5SDimitry Andric cl::init(false), cl::Hidden); 380b57cec5SDimitry Andric 39fe6060f1SDimitry Andric // Print architectural register names rather than the ABI names (such as x2 40fe6060f1SDimitry Andric // instead of sp). 41fe6060f1SDimitry Andric // TODO: Make RISCVInstPrinter::getRegisterName non-static so that this can a 42fe6060f1SDimitry Andric // member. 43fe6060f1SDimitry Andric static bool ArchRegNames; 448bcb0991SDimitry Andric 458bcb0991SDimitry Andric // The command-line flags above are used by llvm-mc and llc. They can be used by 468bcb0991SDimitry Andric // `llvm-objdump`, but we override their values here to handle options passed to 478bcb0991SDimitry Andric // `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to 488bcb0991SDimitry Andric // be an easier way to allow these options in all these tools, without doing it 498bcb0991SDimitry Andric // this way. 508bcb0991SDimitry Andric bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt) { 518bcb0991SDimitry Andric if (Opt == "no-aliases") { 52fe6060f1SDimitry Andric PrintAliases = false; 538bcb0991SDimitry Andric return true; 548bcb0991SDimitry Andric } 558bcb0991SDimitry Andric if (Opt == "numeric") { 568bcb0991SDimitry Andric ArchRegNames = true; 578bcb0991SDimitry Andric return true; 588bcb0991SDimitry Andric } 598bcb0991SDimitry Andric 608bcb0991SDimitry Andric return false; 618bcb0991SDimitry Andric } 628bcb0991SDimitry Andric 63480093f4SDimitry Andric void RISCVInstPrinter::printInst(const MCInst *MI, uint64_t Address, 64480093f4SDimitry Andric StringRef Annot, const MCSubtargetInfo &STI, 65480093f4SDimitry Andric raw_ostream &O) { 660b57cec5SDimitry Andric bool Res = false; 670b57cec5SDimitry Andric const MCInst *NewMI = MI; 680b57cec5SDimitry Andric MCInst UncompressedMI; 69fe6060f1SDimitry Andric if (PrintAliases && !NoAliases) 70bdd1243dSDimitry Andric Res = RISCVRVC::uncompress(UncompressedMI, *MI, STI); 710b57cec5SDimitry Andric if (Res) 720b57cec5SDimitry Andric NewMI = const_cast<MCInst *>(&UncompressedMI); 73fe6060f1SDimitry Andric if (!PrintAliases || NoAliases || !printAliasInstr(NewMI, Address, STI, O)) 74480093f4SDimitry Andric printInstruction(NewMI, Address, STI, O); 750b57cec5SDimitry Andric printAnnotation(O, Annot); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 78bdd1243dSDimitry Andric void RISCVInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const { 795f757f3fSDimitry Andric markup(O, Markup::Register) << getRegisterName(Reg); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 830b57cec5SDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O, 840b57cec5SDimitry Andric const char *Modifier) { 8504eeddc0SDimitry Andric assert((Modifier == nullptr || Modifier[0] == 0) && "No modifiers supported"); 860b57cec5SDimitry Andric const MCOperand &MO = MI->getOperand(OpNo); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric if (MO.isReg()) { 890b57cec5SDimitry Andric printRegName(O, MO.getReg()); 900b57cec5SDimitry Andric return; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric if (MO.isImm()) { 945f757f3fSDimitry Andric markup(O, Markup::Immediate) << formatImm(MO.getImm()); 950b57cec5SDimitry Andric return; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric assert(MO.isExpr() && "Unknown operand kind in printOperand"); 990b57cec5SDimitry Andric MO.getExpr()->print(O, &MAI); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 102e8d8bef9SDimitry Andric void RISCVInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address, 103e8d8bef9SDimitry Andric unsigned OpNo, 104e8d8bef9SDimitry Andric const MCSubtargetInfo &STI, 105e8d8bef9SDimitry Andric raw_ostream &O) { 106e8d8bef9SDimitry Andric const MCOperand &MO = MI->getOperand(OpNo); 107e8d8bef9SDimitry Andric if (!MO.isImm()) 108e8d8bef9SDimitry Andric return printOperand(MI, OpNo, STI, O); 109e8d8bef9SDimitry Andric 110e8d8bef9SDimitry Andric if (PrintBranchImmAsAddress) { 111e8d8bef9SDimitry Andric uint64_t Target = Address + MO.getImm(); 112e8d8bef9SDimitry Andric if (!STI.hasFeature(RISCV::Feature64Bit)) 113e8d8bef9SDimitry Andric Target &= 0xffffffff; 1145f757f3fSDimitry Andric markup(O, Markup::Target) << formatHex(Target); 115e8d8bef9SDimitry Andric } else { 1165f757f3fSDimitry Andric markup(O, Markup::Target) << formatImm(MO.getImm()); 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric } 119e8d8bef9SDimitry Andric 1200b57cec5SDimitry Andric void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo, 1210b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1220b57cec5SDimitry Andric raw_ostream &O) { 1230b57cec5SDimitry Andric unsigned Imm = MI->getOperand(OpNo).getImm(); 124*0fca6ea1SDimitry Andric auto Range = RISCVSysReg::lookupSysRegByEncoding(Imm); 125*0fca6ea1SDimitry Andric for (auto &Reg : Range) { 126*0fca6ea1SDimitry Andric if (Reg.haveRequiredFeatures(STI.getFeatureBits())) { 127*0fca6ea1SDimitry Andric markup(O, Markup::Register) << Reg.Name; 128*0fca6ea1SDimitry Andric return; 129*0fca6ea1SDimitry Andric } 130*0fca6ea1SDimitry Andric } 1315f757f3fSDimitry Andric markup(O, Markup::Register) << formatImm(Imm); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo, 1350b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1360b57cec5SDimitry Andric raw_ostream &O) { 1370b57cec5SDimitry Andric unsigned FenceArg = MI->getOperand(OpNo).getImm(); 1380b57cec5SDimitry Andric assert (((FenceArg >> 4) == 0) && "Invalid immediate in printFenceArg"); 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric if ((FenceArg & RISCVFenceField::I) != 0) 1410b57cec5SDimitry Andric O << 'i'; 1420b57cec5SDimitry Andric if ((FenceArg & RISCVFenceField::O) != 0) 1430b57cec5SDimitry Andric O << 'o'; 1440b57cec5SDimitry Andric if ((FenceArg & RISCVFenceField::R) != 0) 1450b57cec5SDimitry Andric O << 'r'; 1460b57cec5SDimitry Andric if ((FenceArg & RISCVFenceField::W) != 0) 1470b57cec5SDimitry Andric O << 'w'; 1480b57cec5SDimitry Andric if (FenceArg == 0) 14981ad6265SDimitry Andric O << "0"; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo, 1530b57cec5SDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O) { 1540b57cec5SDimitry Andric auto FRMArg = 1550b57cec5SDimitry Andric static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm()); 15606c3fb27SDimitry Andric if (PrintAliases && !NoAliases && FRMArg == RISCVFPRndMode::RoundingMode::DYN) 15706c3fb27SDimitry Andric return; 15806c3fb27SDimitry Andric O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg); 15906c3fb27SDimitry Andric } 16006c3fb27SDimitry Andric 1615f757f3fSDimitry Andric void RISCVInstPrinter::printFRMArgLegacy(const MCInst *MI, unsigned OpNo, 1625f757f3fSDimitry Andric const MCSubtargetInfo &STI, 1635f757f3fSDimitry Andric raw_ostream &O) { 1645f757f3fSDimitry Andric auto FRMArg = 1655f757f3fSDimitry Andric static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm()); 1665f757f3fSDimitry Andric // Never print rounding mode if it's the default 'rne'. This ensures the 1675f757f3fSDimitry Andric // output can still be parsed by older tools that erroneously failed to 1685f757f3fSDimitry Andric // accept a rounding mode. 1695f757f3fSDimitry Andric if (FRMArg == RISCVFPRndMode::RoundingMode::RNE) 1705f757f3fSDimitry Andric return; 1715f757f3fSDimitry Andric O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg); 1725f757f3fSDimitry Andric } 1735f757f3fSDimitry Andric 17406c3fb27SDimitry Andric void RISCVInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNo, 17506c3fb27SDimitry Andric const MCSubtargetInfo &STI, 17606c3fb27SDimitry Andric raw_ostream &O) { 17706c3fb27SDimitry Andric unsigned Imm = MI->getOperand(OpNo).getImm(); 17806c3fb27SDimitry Andric if (Imm == 1) { 1795f757f3fSDimitry Andric markup(O, Markup::Immediate) << "min"; 18006c3fb27SDimitry Andric } else if (Imm == 30) { 1815f757f3fSDimitry Andric markup(O, Markup::Immediate) << "inf"; 18206c3fb27SDimitry Andric } else if (Imm == 31) { 1835f757f3fSDimitry Andric markup(O, Markup::Immediate) << "nan"; 18406c3fb27SDimitry Andric } else { 18506c3fb27SDimitry Andric float FPVal = RISCVLoadFPImm::getFPImm(Imm); 18606c3fb27SDimitry Andric // If the value is an integer, print a .0 fraction. Otherwise, use %g to 18706c3fb27SDimitry Andric // which will not print trailing zeros and will use scientific notation 18806c3fb27SDimitry Andric // if it is shorter than printing as a decimal. The smallest value requires 18906c3fb27SDimitry Andric // 12 digits of precision including the decimal. 19006c3fb27SDimitry Andric if (FPVal == (int)(FPVal)) 1915f757f3fSDimitry Andric markup(O, Markup::Immediate) << format("%.1f", FPVal); 19206c3fb27SDimitry Andric else 1935f757f3fSDimitry Andric markup(O, Markup::Immediate) << format("%.12g", FPVal); 19406c3fb27SDimitry Andric } 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 19781ad6265SDimitry Andric void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo, 1980b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1990b57cec5SDimitry Andric raw_ostream &O) { 2000b57cec5SDimitry Andric const MCOperand &MO = MI->getOperand(OpNo); 2010b57cec5SDimitry Andric 20281ad6265SDimitry Andric assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands"); 2030b57cec5SDimitry Andric O << "("; 2040b57cec5SDimitry Andric printRegName(O, MO.getReg()); 2050b57cec5SDimitry Andric O << ")"; 2060b57cec5SDimitry Andric } 2078bcb0991SDimitry Andric 2085ffd83dbSDimitry Andric void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo, 2095ffd83dbSDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O) { 2105ffd83dbSDimitry Andric unsigned Imm = MI->getOperand(OpNo).getImm(); 2114824e7fdSDimitry Andric // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx, 2120eae32dcSDimitry Andric // or non-zero in bits 8 and above. 2134824e7fdSDimitry Andric if (RISCVVType::getVLMUL(Imm) == RISCVII::VLMUL::LMUL_RESERVED || 2140eae32dcSDimitry Andric RISCVVType::getSEW(Imm) > 64 || (Imm >> 8) != 0) { 2155f757f3fSDimitry Andric O << formatImm(Imm); 2164824e7fdSDimitry Andric return; 2174824e7fdSDimitry Andric } 2184824e7fdSDimitry Andric // Print the text form. 219e8d8bef9SDimitry Andric RISCVVType::printVType(Imm, O); 2205ffd83dbSDimitry Andric } 2215ffd83dbSDimitry Andric 222*0fca6ea1SDimitry Andric // Print a Zcmp RList. If we are printing architectural register names rather 223*0fca6ea1SDimitry Andric // than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all 224*0fca6ea1SDimitry Andric // registers. Otherwise, we print "{ra, s0-s11}". 22506c3fb27SDimitry Andric void RISCVInstPrinter::printRlist(const MCInst *MI, unsigned OpNo, 22606c3fb27SDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O) { 22706c3fb27SDimitry Andric unsigned Imm = MI->getOperand(OpNo).getImm(); 22806c3fb27SDimitry Andric O << "{"; 229*0fca6ea1SDimitry Andric printRegName(O, RISCV::X1); 230*0fca6ea1SDimitry Andric 231*0fca6ea1SDimitry Andric if (Imm >= RISCVZC::RLISTENCODE::RA_S0) { 2325f757f3fSDimitry Andric O << ", "; 233*0fca6ea1SDimitry Andric printRegName(O, RISCV::X8); 2345f757f3fSDimitry Andric } 235*0fca6ea1SDimitry Andric 236*0fca6ea1SDimitry Andric if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S1) { 2375f757f3fSDimitry Andric O << '-'; 238*0fca6ea1SDimitry Andric if (Imm == RISCVZC::RLISTENCODE::RA_S0_S1 || ArchRegNames) 239*0fca6ea1SDimitry Andric printRegName(O, RISCV::X9); 240*0fca6ea1SDimitry Andric } 241*0fca6ea1SDimitry Andric 242*0fca6ea1SDimitry Andric if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S2) { 243*0fca6ea1SDimitry Andric if (ArchRegNames) 2445f757f3fSDimitry Andric O << ", "; 245*0fca6ea1SDimitry Andric if (Imm == RISCVZC::RLISTENCODE::RA_S0_S2 || ArchRegNames) 246*0fca6ea1SDimitry Andric printRegName(O, RISCV::X18); 247*0fca6ea1SDimitry Andric } 248*0fca6ea1SDimitry Andric 249*0fca6ea1SDimitry Andric if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S3) { 250*0fca6ea1SDimitry Andric if (ArchRegNames) 2515f757f3fSDimitry Andric O << '-'; 252*0fca6ea1SDimitry Andric unsigned Offset = (Imm - RISCVZC::RLISTENCODE::RA_S0_S3); 253*0fca6ea1SDimitry Andric // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we 254*0fca6ea1SDimitry Andric // must skip to S11(X27). 255*0fca6ea1SDimitry Andric if (Imm == RISCVZC::RLISTENCODE::RA_S0_S11) 256*0fca6ea1SDimitry Andric ++Offset; 257*0fca6ea1SDimitry Andric printRegName(O, RISCV::X19 + Offset); 2585f757f3fSDimitry Andric } 259*0fca6ea1SDimitry Andric 26006c3fb27SDimitry Andric O << "}"; 26106c3fb27SDimitry Andric } 26206c3fb27SDimitry Andric 2635f757f3fSDimitry Andric void RISCVInstPrinter::printRegReg(const MCInst *MI, unsigned OpNo, 2645f757f3fSDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O) { 2655f757f3fSDimitry Andric const MCOperand &MO = MI->getOperand(OpNo); 2665f757f3fSDimitry Andric 2675f757f3fSDimitry Andric assert(MO.isReg() && "printRegReg can only print register operands"); 2685f757f3fSDimitry Andric if (MO.getReg() == RISCV::NoRegister) 2695f757f3fSDimitry Andric return; 2705f757f3fSDimitry Andric printRegName(O, MO.getReg()); 2715f757f3fSDimitry Andric 2725f757f3fSDimitry Andric O << "("; 2735f757f3fSDimitry Andric const MCOperand &MO1 = MI->getOperand(OpNo + 1); 2745f757f3fSDimitry Andric assert(MO1.isReg() && "printRegReg can only print register operands"); 2755f757f3fSDimitry Andric printRegName(O, MO1.getReg()); 2765f757f3fSDimitry Andric O << ")"; 2775f757f3fSDimitry Andric } 2785f757f3fSDimitry Andric 279*0fca6ea1SDimitry Andric void RISCVInstPrinter::printStackAdj(const MCInst *MI, unsigned OpNo, 280*0fca6ea1SDimitry Andric const MCSubtargetInfo &STI, raw_ostream &O, 281*0fca6ea1SDimitry Andric bool Negate) { 28206c3fb27SDimitry Andric int64_t Imm = MI->getOperand(OpNo).getImm(); 28306c3fb27SDimitry Andric bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); 284*0fca6ea1SDimitry Andric int64_t StackAdj = 0; 28506c3fb27SDimitry Andric auto RlistVal = MI->getOperand(0).getImm(); 28606c3fb27SDimitry Andric assert(RlistVal != 16 && "Incorrect rlist."); 287*0fca6ea1SDimitry Andric auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64); 288*0fca6ea1SDimitry Andric StackAdj = Imm + Base; 289*0fca6ea1SDimitry Andric assert((StackAdj >= Base && StackAdj <= Base + 48) && 290*0fca6ea1SDimitry Andric "Incorrect stack adjust"); 291*0fca6ea1SDimitry Andric if (Negate) 292*0fca6ea1SDimitry Andric StackAdj = -StackAdj; 29306c3fb27SDimitry Andric 2945f757f3fSDimitry Andric // RAII guard for ANSI color escape sequences 2955f757f3fSDimitry Andric WithMarkup ScopedMarkup = markup(O, Markup::Immediate); 296*0fca6ea1SDimitry Andric O << StackAdj; 29706c3fb27SDimitry Andric } 29806c3fb27SDimitry Andric 2995ffd83dbSDimitry Andric void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo, 3005ffd83dbSDimitry Andric const MCSubtargetInfo &STI, 3015ffd83dbSDimitry Andric raw_ostream &O) { 3025ffd83dbSDimitry Andric const MCOperand &MO = MI->getOperand(OpNo); 3035ffd83dbSDimitry Andric 3045ffd83dbSDimitry Andric assert(MO.isReg() && "printVMaskReg can only print register operands"); 3055ffd83dbSDimitry Andric if (MO.getReg() == RISCV::NoRegister) 3065ffd83dbSDimitry Andric return; 3075ffd83dbSDimitry Andric O << ", "; 3085ffd83dbSDimitry Andric printRegName(O, MO.getReg()); 3095ffd83dbSDimitry Andric O << ".t"; 3105ffd83dbSDimitry Andric } 3115ffd83dbSDimitry Andric 312bdd1243dSDimitry Andric const char *RISCVInstPrinter::getRegisterName(MCRegister Reg) { 313bdd1243dSDimitry Andric return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName 3148bcb0991SDimitry Andric : RISCV::ABIRegAltName); 3158bcb0991SDimitry Andric } 316