1 //===-- RISCVInstPrinter.cpp - Convert RISC-V MCInst to asm syntax --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This class prints an RISC-V MCInst to a .s file. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "RISCVInstPrinter.h" 14 #include "RISCVBaseInfo.h" 15 #include "RISCVMCExpr.h" 16 #include "llvm/MC/MCAsmInfo.h" 17 #include "llvm/MC/MCExpr.h" 18 #include "llvm/MC/MCInst.h" 19 #include "llvm/MC/MCInstPrinter.h" 20 #include "llvm/MC/MCRegisterInfo.h" 21 #include "llvm/MC/MCSubtargetInfo.h" 22 #include "llvm/MC/MCSymbol.h" 23 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/FormattedStream.h" 26 using namespace llvm; 27 28 #define DEBUG_TYPE "asm-printer" 29 30 // Include the auto-generated portion of the assembly writer. 31 #define PRINT_ALIAS_INSTR 32 #include "RISCVGenAsmWriter.inc" 33 34 static cl::opt<bool> 35 NoAliases("riscv-no-aliases", 36 cl::desc("Disable the emission of assembler pseudo instructions"), 37 cl::init(false), cl::Hidden); 38 39 // Print architectural register names rather than the ABI names (such as x2 40 // instead of sp). 41 // TODO: Make RISCVInstPrinter::getRegisterName non-static so that this can a 42 // member. 43 static bool ArchRegNames; 44 45 // The command-line flags above are used by llvm-mc and llc. They can be used by 46 // `llvm-objdump`, but we override their values here to handle options passed to 47 // `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to 48 // be an easier way to allow these options in all these tools, without doing it 49 // this way. 50 bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt) { 51 if (Opt == "no-aliases") { 52 PrintAliases = false; 53 return true; 54 } 55 if (Opt == "numeric") { 56 ArchRegNames = true; 57 return true; 58 } 59 60 return false; 61 } 62 63 void RISCVInstPrinter::printInst(const MCInst *MI, uint64_t Address, 64 StringRef Annot, const MCSubtargetInfo &STI, 65 raw_ostream &O) { 66 bool Res = false; 67 const MCInst *NewMI = MI; 68 MCInst UncompressedMI; 69 if (PrintAliases && !NoAliases) 70 Res = RISCVRVC::uncompress(UncompressedMI, *MI, STI); 71 if (Res) 72 NewMI = const_cast<MCInst *>(&UncompressedMI); 73 if (!PrintAliases || NoAliases || !printAliasInstr(NewMI, Address, STI, O)) 74 printInstruction(NewMI, Address, STI, O); 75 printAnnotation(O, Annot); 76 } 77 78 void RISCVInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const { 79 markup(O, Markup::Register) << getRegisterName(Reg); 80 } 81 82 void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 83 const MCSubtargetInfo &STI, raw_ostream &O, 84 const char *Modifier) { 85 assert((Modifier == nullptr || Modifier[0] == 0) && "No modifiers supported"); 86 const MCOperand &MO = MI->getOperand(OpNo); 87 88 if (MO.isReg()) { 89 printRegName(O, MO.getReg()); 90 return; 91 } 92 93 if (MO.isImm()) { 94 markup(O, Markup::Immediate) << MO.getImm(); 95 return; 96 } 97 98 assert(MO.isExpr() && "Unknown operand kind in printOperand"); 99 MO.getExpr()->print(O, &MAI); 100 } 101 102 void RISCVInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address, 103 unsigned OpNo, 104 const MCSubtargetInfo &STI, 105 raw_ostream &O) { 106 const MCOperand &MO = MI->getOperand(OpNo); 107 if (!MO.isImm()) 108 return printOperand(MI, OpNo, STI, O); 109 110 if (PrintBranchImmAsAddress) { 111 uint64_t Target = Address + MO.getImm(); 112 if (!STI.hasFeature(RISCV::Feature64Bit)) 113 Target &= 0xffffffff; 114 markup(O, Markup::Target) << formatHex(Target); 115 } else { 116 markup(O, Markup::Target) << MO.getImm(); 117 } 118 } 119 120 void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo, 121 const MCSubtargetInfo &STI, 122 raw_ostream &O) { 123 unsigned Imm = MI->getOperand(OpNo).getImm(); 124 auto SiFiveReg = RISCVSysReg::lookupSiFiveRegByEncoding(Imm); 125 auto SysReg = RISCVSysReg::lookupSysRegByEncoding(Imm); 126 if (SiFiveReg && SiFiveReg->haveVendorRequiredFeatures(STI.getFeatureBits())) 127 markup(O, Markup::Register) << SiFiveReg->Name; 128 else if (SysReg && SysReg->haveRequiredFeatures(STI.getFeatureBits())) 129 markup(O, Markup::Register) << SysReg->Name; 130 else 131 markup(O, Markup::Register) << Imm; 132 } 133 134 void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo, 135 const MCSubtargetInfo &STI, 136 raw_ostream &O) { 137 unsigned FenceArg = MI->getOperand(OpNo).getImm(); 138 assert (((FenceArg >> 4) == 0) && "Invalid immediate in printFenceArg"); 139 140 if ((FenceArg & RISCVFenceField::I) != 0) 141 O << 'i'; 142 if ((FenceArg & RISCVFenceField::O) != 0) 143 O << 'o'; 144 if ((FenceArg & RISCVFenceField::R) != 0) 145 O << 'r'; 146 if ((FenceArg & RISCVFenceField::W) != 0) 147 O << 'w'; 148 if (FenceArg == 0) 149 O << "0"; 150 } 151 152 void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo, 153 const MCSubtargetInfo &STI, raw_ostream &O) { 154 auto FRMArg = 155 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm()); 156 if (PrintAliases && !NoAliases && FRMArg == RISCVFPRndMode::RoundingMode::DYN) 157 return; 158 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg); 159 } 160 161 void RISCVInstPrinter::printFRMArgLegacy(const MCInst *MI, unsigned OpNo, 162 const MCSubtargetInfo &STI, 163 raw_ostream &O) { 164 auto FRMArg = 165 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm()); 166 // Never print rounding mode if it's the default 'rne'. This ensures the 167 // output can still be parsed by older tools that erroneously failed to 168 // accept a rounding mode. 169 if (FRMArg == RISCVFPRndMode::RoundingMode::RNE) 170 return; 171 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg); 172 } 173 174 void RISCVInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNo, 175 const MCSubtargetInfo &STI, 176 raw_ostream &O) { 177 unsigned Imm = MI->getOperand(OpNo).getImm(); 178 if (Imm == 1) { 179 markup(O, Markup::Immediate) << "min"; 180 } else if (Imm == 30) { 181 markup(O, Markup::Immediate) << "inf"; 182 } else if (Imm == 31) { 183 markup(O, Markup::Immediate) << "nan"; 184 } else { 185 float FPVal = RISCVLoadFPImm::getFPImm(Imm); 186 // If the value is an integer, print a .0 fraction. Otherwise, use %g to 187 // which will not print trailing zeros and will use scientific notation 188 // if it is shorter than printing as a decimal. The smallest value requires 189 // 12 digits of precision including the decimal. 190 if (FPVal == (int)(FPVal)) 191 markup(O, Markup::Immediate) << format("%.1f", FPVal); 192 else 193 markup(O, Markup::Immediate) << format("%.12g", FPVal); 194 } 195 } 196 197 void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo, 198 const MCSubtargetInfo &STI, 199 raw_ostream &O) { 200 const MCOperand &MO = MI->getOperand(OpNo); 201 202 assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands"); 203 O << "("; 204 printRegName(O, MO.getReg()); 205 O << ")"; 206 } 207 208 void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo, 209 const MCSubtargetInfo &STI, raw_ostream &O) { 210 unsigned Imm = MI->getOperand(OpNo).getImm(); 211 // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx, 212 // or non-zero in bits 8 and above. 213 if (RISCVVType::getVLMUL(Imm) == RISCVII::VLMUL::LMUL_RESERVED || 214 RISCVVType::getSEW(Imm) > 64 || (Imm >> 8) != 0) { 215 O << Imm; 216 return; 217 } 218 // Print the text form. 219 RISCVVType::printVType(Imm, O); 220 } 221 222 void RISCVInstPrinter::printRlist(const MCInst *MI, unsigned OpNo, 223 const MCSubtargetInfo &STI, raw_ostream &O) { 224 unsigned Imm = MI->getOperand(OpNo).getImm(); 225 O << "{"; 226 switch (Imm) { 227 case RISCVZC::RLISTENCODE::RA: 228 markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra"); 229 break; 230 case RISCVZC::RLISTENCODE::RA_S0: 231 markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra"); 232 O << ", "; 233 markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0"); 234 break; 235 case RISCVZC::RLISTENCODE::RA_S0_S1: 236 markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra"); 237 O << ", "; 238 markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0"); 239 O << '-'; 240 markup(O, Markup::Register) << (ArchRegNames ? "x9" : "s1"); 241 break; 242 case RISCVZC::RLISTENCODE::RA_S0_S2: 243 markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra"); 244 O << ", "; 245 markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0"); 246 O << '-'; 247 markup(O, Markup::Register) << (ArchRegNames ? "x9" : "s2"); 248 if (ArchRegNames) { 249 O << ", "; 250 markup(O, Markup::Register) << "x18"; 251 } 252 break; 253 case RISCVZC::RLISTENCODE::RA_S0_S3: 254 case RISCVZC::RLISTENCODE::RA_S0_S4: 255 case RISCVZC::RLISTENCODE::RA_S0_S5: 256 case RISCVZC::RLISTENCODE::RA_S0_S6: 257 case RISCVZC::RLISTENCODE::RA_S0_S7: 258 case RISCVZC::RLISTENCODE::RA_S0_S8: 259 case RISCVZC::RLISTENCODE::RA_S0_S9: 260 case RISCVZC::RLISTENCODE::RA_S0_S11: 261 markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra"); 262 O << ", "; 263 markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0"); 264 O << '-'; 265 if (ArchRegNames) { 266 markup(O, Markup::Register) << "x9"; 267 O << ", "; 268 markup(O, Markup::Register) << "x18"; 269 O << '-'; 270 } 271 markup(O, Markup::Register) << getRegisterName( 272 RISCV::X19 + (Imm == RISCVZC::RLISTENCODE::RA_S0_S11 273 ? 8 274 : Imm - RISCVZC::RLISTENCODE::RA_S0_S3)); 275 break; 276 default: 277 llvm_unreachable("invalid register list"); 278 } 279 O << "}"; 280 } 281 282 void RISCVInstPrinter::printSpimm(const MCInst *MI, unsigned OpNo, 283 const MCSubtargetInfo &STI, raw_ostream &O) { 284 int64_t Imm = MI->getOperand(OpNo).getImm(); 285 unsigned Opcode = MI->getOpcode(); 286 bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); 287 bool IsEABI = STI.hasFeature(RISCV::FeatureRVE); 288 int64_t Spimm = 0; 289 auto RlistVal = MI->getOperand(0).getImm(); 290 assert(RlistVal != 16 && "Incorrect rlist."); 291 auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64, IsEABI); 292 Spimm = Imm + Base; 293 assert((Spimm >= Base && Spimm <= Base + 48) && "Incorrect spimm"); 294 if (Opcode == RISCV::CM_PUSH) 295 Spimm = -Spimm; 296 297 // RAII guard for ANSI color escape sequences 298 WithMarkup ScopedMarkup = markup(O, Markup::Immediate); 299 RISCVZC::printSpimm(Spimm, O); 300 } 301 302 void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo, 303 const MCSubtargetInfo &STI, 304 raw_ostream &O) { 305 const MCOperand &MO = MI->getOperand(OpNo); 306 307 assert(MO.isReg() && "printVMaskReg can only print register operands"); 308 if (MO.getReg() == RISCV::NoRegister) 309 return; 310 O << ", "; 311 printRegName(O, MO.getReg()); 312 O << ".t"; 313 } 314 315 const char *RISCVInstPrinter::getRegisterName(MCRegister Reg) { 316 return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName 317 : RISCV::ABIRegAltName); 318 } 319