349 lines · cpp
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-exception6//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 "llvm/MC/MCAsmInfo.h"16#include "llvm/MC/MCExpr.h"17#include "llvm/MC/MCInst.h"18#include "llvm/MC/MCInstPrinter.h"19#include "llvm/MC/MCSubtargetInfo.h"20#include "llvm/MC/MCSymbol.h"21#include "llvm/Support/CommandLine.h"22#include "llvm/Support/ErrorHandling.h"23using namespace llvm;24 25#define DEBUG_TYPE "asm-printer"26 27// Include the auto-generated portion of the assembly writer.28#define PRINT_ALIAS_INSTR29#include "RISCVGenAsmWriter.inc"30 31static cl::opt<bool>32 NoAliases("riscv-no-aliases",33 cl::desc("Disable the emission of assembler pseudo instructions"),34 cl::init(false), cl::Hidden);35 36static cl::opt<bool> EmitX8AsFP("riscv-emit-x8-as-fp",37 cl::desc("Emit x8 as fp instead of s0"),38 cl::init(false), cl::Hidden);39 40// Print architectural register names rather than the ABI names (such as x241// instead of sp).42// TODO: Make RISCVInstPrinter::getRegisterName non-static so that this can a43// member.44static bool ArchRegNames;45 46// The command-line flags above are used by llvm-mc and llc. They can be used by47// `llvm-objdump`, but we override their values here to handle options passed to48// `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to49// be an easier way to allow these options in all these tools, without doing it50// this way.51bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt) {52 if (Opt == "no-aliases") {53 PrintAliases = false;54 return true;55 }56 if (Opt == "numeric") {57 ArchRegNames = true;58 return true;59 }60 if (Opt == "emit-x8-as-fp") {61 if (!ArchRegNames)62 EmitX8AsFP = true;63 return true;64 }65 66 return false;67}68 69void RISCVInstPrinter::printInst(const MCInst *MI, uint64_t Address,70 StringRef Annot, const MCSubtargetInfo &STI,71 raw_ostream &O) {72 bool Res = false;73 const MCInst *NewMI = MI;74 MCInst UncompressedMI;75 if (PrintAliases && !NoAliases)76 Res = RISCVRVC::uncompress(UncompressedMI, *MI, STI);77 if (Res)78 NewMI = &UncompressedMI;79 if (!PrintAliases || NoAliases || !printAliasInstr(NewMI, Address, STI, O))80 printInstruction(NewMI, Address, STI, O);81 printAnnotation(O, Annot);82}83 84void RISCVInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) {85 markup(O, Markup::Register) << getRegisterName(Reg);86}87 88void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,89 const MCSubtargetInfo &STI,90 raw_ostream &O) {91 const MCOperand &MO = MI->getOperand(OpNo);92 93 if (MO.isReg()) {94 printRegName(O, MO.getReg());95 return;96 }97 98 if (MO.isImm()) {99 markup(O, Markup::Immediate) << formatImm(MO.getImm());100 return;101 }102 103 assert(MO.isExpr() && "Unknown operand kind in printOperand");104 MAI.printExpr(O, *MO.getExpr());105}106 107void RISCVInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address,108 unsigned OpNo,109 const MCSubtargetInfo &STI,110 raw_ostream &O) {111 const MCOperand &MO = MI->getOperand(OpNo);112 if (!MO.isImm())113 return printOperand(MI, OpNo, STI, O);114 115 if (PrintBranchImmAsAddress) {116 uint64_t Target = Address + MO.getImm();117 if (!STI.hasFeature(RISCV::Feature64Bit))118 Target &= 0xffffffff;119 markup(O, Markup::Target) << formatHex(Target);120 } else {121 markup(O, Markup::Target) << formatImm(MO.getImm());122 }123}124 125void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo,126 const MCSubtargetInfo &STI,127 raw_ostream &O) {128 unsigned Imm = MI->getOperand(OpNo).getImm();129 auto Range = RISCVSysReg::lookupSysRegByEncoding(Imm);130 for (auto &Reg : Range) {131 if (Reg.IsAltName || Reg.IsDeprecatedName)132 continue;133 if (Reg.haveRequiredFeatures(STI.getFeatureBits())) {134 markup(O, Markup::Register) << Reg.Name;135 return;136 }137 }138 markup(O, Markup::Register) << formatImm(Imm);139}140 141void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,142 const MCSubtargetInfo &STI,143 raw_ostream &O) {144 unsigned FenceArg = MI->getOperand(OpNo).getImm();145 assert (((FenceArg >> 4) == 0) && "Invalid immediate in printFenceArg");146 147 if ((FenceArg & RISCVFenceField::I) != 0)148 O << 'i';149 if ((FenceArg & RISCVFenceField::O) != 0)150 O << 'o';151 if ((FenceArg & RISCVFenceField::R) != 0)152 O << 'r';153 if ((FenceArg & RISCVFenceField::W) != 0)154 O << 'w';155 if (FenceArg == 0)156 O << "0";157}158 159void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo,160 const MCSubtargetInfo &STI, raw_ostream &O) {161 auto FRMArg =162 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());163 if (PrintAliases && !NoAliases && FRMArg == RISCVFPRndMode::RoundingMode::DYN)164 return;165 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);166}167 168void RISCVInstPrinter::printFRMArgLegacy(const MCInst *MI, unsigned OpNo,169 const MCSubtargetInfo &STI,170 raw_ostream &O) {171 auto FRMArg =172 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());173 // Never print rounding mode if it's the default 'rne'. This ensures the174 // output can still be parsed by older tools that erroneously failed to175 // accept a rounding mode.176 if (FRMArg == RISCVFPRndMode::RoundingMode::RNE)177 return;178 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);179}180 181void RISCVInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNo,182 const MCSubtargetInfo &STI,183 raw_ostream &O) {184 unsigned Imm = MI->getOperand(OpNo).getImm();185 if (Imm == 1) {186 markup(O, Markup::Immediate) << "min";187 } else if (Imm == 30) {188 markup(O, Markup::Immediate) << "inf";189 } else if (Imm == 31) {190 markup(O, Markup::Immediate) << "nan";191 } else {192 float FPVal = RISCVLoadFPImm::getFPImm(Imm);193 // If the value is an integer, print a .0 fraction. Otherwise, use %g to194 // which will not print trailing zeros and will use scientific notation195 // if it is shorter than printing as a decimal. The smallest value requires196 // 12 digits of precision including the decimal.197 if (FPVal == (int)(FPVal))198 markup(O, Markup::Immediate) << format("%.1f", FPVal);199 else200 markup(O, Markup::Immediate) << format("%.12g", FPVal);201 }202}203 204void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo,205 const MCSubtargetInfo &STI,206 raw_ostream &O) {207 const MCOperand &MO = MI->getOperand(OpNo);208 209 assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands");210 O << "(";211 printRegName(O, MO.getReg());212 O << ")";213}214 215void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,216 const MCSubtargetInfo &STI, raw_ostream &O) {217 unsigned Imm = MI->getOperand(OpNo).getImm();218 // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx,219 // altfmt=1 without zvfbfa extension, or non-zero in bits 9 and above.220 if (RISCVVType::getVLMUL(Imm) == RISCVVType::VLMUL::LMUL_RESERVED ||221 RISCVVType::getSEW(Imm) > 64 ||222 (RISCVVType::isAltFmt(Imm) &&223 !(STI.hasFeature(RISCV::FeatureStdExtZvfbfa) ||224 STI.hasFeature(RISCV::FeatureVendorXSfvfbfexp16e))) ||225 (Imm >> 9) != 0) {226 O << formatImm(Imm);227 return;228 }229 // Print the text form.230 RISCVVType::printVType(Imm, O);231}232 233void RISCVInstPrinter::printXSfmmVType(const MCInst *MI, unsigned OpNo,234 const MCSubtargetInfo &STI,235 raw_ostream &O) {236 unsigned Imm = MI->getOperand(OpNo).getImm();237 assert(RISCVVType::isValidXSfmmVType(Imm));238 unsigned SEW = RISCVVType::getSEW(Imm);239 O << "e" << SEW;240 bool AltFmt = RISCVVType::isAltFmt(Imm);241 if (AltFmt)242 O << "alt";243 unsigned Widen = RISCVVType::getXSfmmWiden(Imm);244 O << ", w" << Widen;245}246 247// Print a Zcmp RList. If we are printing architectural register names rather248// than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all249// registers. Otherwise, we print "{ra, s0-s11}".250void RISCVInstPrinter::printRegList(const MCInst *MI, unsigned OpNo,251 const MCSubtargetInfo &STI, raw_ostream &O) {252 unsigned Imm = MI->getOperand(OpNo).getImm();253 254 assert(Imm >= RISCVZC::RLISTENCODE::RA &&255 Imm <= RISCVZC::RLISTENCODE::RA_S0_S11 && "Invalid Rlist");256 257 O << "{";258 printRegName(O, RISCV::X1);259 260 if (Imm >= RISCVZC::RLISTENCODE::RA_S0) {261 O << ", ";262 printRegName(O, RISCV::X8);263 }264 265 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S1) {266 O << '-';267 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S1 || ArchRegNames)268 printRegName(O, RISCV::X9);269 }270 271 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S2) {272 if (ArchRegNames)273 O << ", ";274 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S2 || ArchRegNames)275 printRegName(O, RISCV::X18);276 }277 278 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S3) {279 if (ArchRegNames)280 O << '-';281 unsigned Offset = (Imm - RISCVZC::RLISTENCODE::RA_S0_S3);282 // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we283 // must skip to S11(X27).284 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S11)285 ++Offset;286 printRegName(O, RISCV::X19 + Offset);287 }288 289 O << "}";290}291 292void RISCVInstPrinter::printRegReg(const MCInst *MI, unsigned OpNo,293 const MCSubtargetInfo &STI, raw_ostream &O) {294 const MCOperand &OffsetMO = MI->getOperand(OpNo + 1);295 296 assert(OffsetMO.isReg() && "printRegReg can only print register operands");297 printRegName(O, OffsetMO.getReg());298 299 O << "(";300 const MCOperand &BaseMO = MI->getOperand(OpNo);301 assert(BaseMO.isReg() && "printRegReg can only print register operands");302 printRegName(O, BaseMO.getReg());303 O << ")";304}305 306void RISCVInstPrinter::printStackAdj(const MCInst *MI, unsigned OpNo,307 const MCSubtargetInfo &STI, raw_ostream &O,308 bool Negate) {309 int64_t Imm = MI->getOperand(OpNo).getImm();310 bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);311 int64_t StackAdj = 0;312 auto RlistVal = MI->getOperand(0).getImm();313 auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64);314 StackAdj = Imm + Base;315 assert((StackAdj >= Base && StackAdj <= Base + 48) &&316 "Incorrect stack adjust");317 if (Negate)318 StackAdj = -StackAdj;319 320 // RAII guard for ANSI color escape sequences321 WithMarkup ScopedMarkup = markup(O, Markup::Immediate);322 O << StackAdj;323}324 325void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo,326 const MCSubtargetInfo &STI,327 raw_ostream &O) {328 const MCOperand &MO = MI->getOperand(OpNo);329 330 assert(MO.isReg() && "printVMaskReg can only print register operands");331 if (MO.getReg() == RISCV::NoRegister)332 return;333 O << ", ";334 printRegName(O, MO.getReg());335 O << ".t";336}337 338const char *RISCVInstPrinter::getRegisterName(MCRegister Reg) {339 // When PrintAliases is enabled, and EmitX8AsFP is enabled, x8 will be printed340 // as fp instead of s0. Note that these similar registers are not replaced:341 // - X8_H: used for f16 register in zhinx342 // - X8_W: used for f32 register in zfinx343 // - X8_X9: used for GPR Pair344 if (!ArchRegNames && EmitX8AsFP && Reg == RISCV::X8)345 return "fp";346 return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName347 : RISCV::ABIRegAltName);348}349