LLVM 24.0.0git
RISCVInstPrinter.cpp
Go to the documentation of this file.
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 "RISCVMCAsmInfo.h"
16#include "llvm/MC/MCAsmInfo.h"
17#include "llvm/MC/MCExpr.h"
18#include "llvm/MC/MCInst.h"
22#include "llvm/MC/MCSymbol.h"
24using namespace llvm;
25
26#define DEBUG_TYPE "asm-printer"
27
28// Include the auto-generated portion of the assembly writer.
29#define PRINT_ALIAS_INSTR
30#include "RISCVGenAsmWriter.inc"
31
32// Print architectural register names rather than the ABI names (such as x2
33// instead of sp).
34// TODO: Make RISCVInstPrinter::getRegisterName non-static so that this and
35// EmitX8AsFP can be members.
36static bool ArchRegNames;
37static bool EmitX8AsFP;
38
39// -riscv-no-aliases and -riscv-emit-x8-as-fp are used by llvm-mc and llc. They
40// can be used by `llvm-objdump`, but we override their values here to handle
41// options passed to `llvm-objdump` with `-M` (which matches GNU objdump). There
42// did not seem to be an easier way to allow these options in all these tools,
43// without doing it this way.
45 if (Opt == "no-aliases") {
46 PrintAliases = false;
47 return true;
48 }
49 if (Opt == "numeric") {
50 ArchRegNames = true;
51 return true;
52 }
53 if (Opt == "emit-x8-as-fp") {
54 if (!ArchRegNames)
55 EmitX8AsFP = true;
56 return true;
57 }
58
59 return false;
60}
61
63 StringRef Annot, const MCSubtargetInfo &STI,
64 raw_ostream &O) {
65 bool Res = false;
66 const MCInst *NewMI = MI;
67 MCInst UncompressedMI;
68 if (PrintAliases && !CLOpts.no_aliases)
69 Res = RISCVRVC::uncompress(UncompressedMI, *MI, STI);
70 if (Res)
71 NewMI = &UncompressedMI;
72 if (!PrintAliases || CLOpts.no_aliases ||
73 !printAliasInstr(NewMI, Address, STI, O))
74 printInstruction(NewMI, Address, STI, O);
75 printAnnotation(O, Annot);
76}
77
81
82void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
83 const MCSubtargetInfo &STI,
84 raw_ostream &O) {
85 const MCOperand &MO = MI->getOperand(OpNo);
86
87 if (MO.isReg()) {
88 printRegName(O, MO.getReg());
89 return;
90 }
91
92 if (MO.isImm()) {
93 printImm(MI, OpNo, STI, O);
94 return;
95 }
96
97 assert(MO.isExpr() && "Unknown operand kind in printOperand");
98 MAI.printExpr(O, *MO.getExpr());
99}
100
102 unsigned OpNo,
103 const MCSubtargetInfo &STI,
104 raw_ostream &O) {
105 // Do not print the numeric target address when symbolizing.
107 return;
108
109 const MCOperand &MO = MI->getOperand(OpNo);
110 if (!MO.isImm())
111 return printOperand(MI, OpNo, STI, O);
112
114 uint64_t Target = Address + MO.getImm();
115 if (!STI.hasFeature(RISCV::Feature64Bit))
116 Target &= 0xffffffff;
118 } else {
120 }
121}
122
124 const MCSubtargetInfo &STI,
125 raw_ostream &O) {
126 unsigned Imm = MI->getOperand(OpNo).getImm();
127 auto Range = RISCVSysReg::lookupSysRegByEncoding(Imm);
128 bool PreferFeatureSpecific = llvm::any_of(Range, [&](const auto &Reg) {
129 return !Reg.IsAltName && !Reg.IsDeprecatedName &&
130 Reg.FeaturesRequired.any() &&
131 Reg.haveRequiredFeatures(STI.getFeatureBits());
132 });
133 for (auto &Reg : Range) {
134 if (Reg.IsAltName || Reg.IsDeprecatedName)
135 continue;
136 if (Reg.haveRequiredFeatures(STI.getFeatureBits()) &&
137 (!PreferFeatureSpecific || Reg.FeaturesRequired.any())) {
138 markup(O, Markup::Register) << RISCVSysReg::getSysRegStr(Reg.Name);
139 return;
140 }
141 }
143}
144
145void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
146 const MCSubtargetInfo &STI,
147 raw_ostream &O) {
148 unsigned FenceArg = MI->getOperand(OpNo).getImm();
149 assert (((FenceArg >> 4) == 0) && "Invalid immediate in printFenceArg");
150
151 if ((FenceArg & RISCVFenceField::I) != 0)
152 O << 'i';
153 if ((FenceArg & RISCVFenceField::O) != 0)
154 O << 'o';
155 if ((FenceArg & RISCVFenceField::R) != 0)
156 O << 'r';
157 if ((FenceArg & RISCVFenceField::W) != 0)
158 O << 'w';
159 if (FenceArg == 0)
160 O << "0";
161}
162
163void RISCVInstPrinter::printSMTVType(const MCInst *MI, unsigned OpNo,
164 const MCSubtargetInfo &STI,
165 raw_ostream &O) {
166 auto VType =
167 static_cast<XSMTVTypeMode::SMTVTypeMode>(MI->getOperand(OpNo).getImm());
169 "SpacemiT's Integer Matrix only supports [i4|i8] mode");
170 O << ", " << XSMTVTypeMode::SMTVTypeModeToString(VType);
171}
172
173void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo,
174 const MCSubtargetInfo &STI, raw_ostream &O) {
175 auto FRMArg =
176 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
177 if (PrintAliases && !CLOpts.no_aliases &&
179 return;
180 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
181}
182
184 const MCSubtargetInfo &STI,
185 raw_ostream &O) {
186 auto FRMArg =
187 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
188 // Never print rounding mode if it's the default 'rne'. This ensures the
189 // output can still be parsed by older tools that erroneously failed to
190 // accept a rounding mode.
192 return;
193 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
194}
195
197 const MCSubtargetInfo &STI,
198 raw_ostream &O) {
199 unsigned Imm = MI->getOperand(OpNo).getImm();
200 if (Imm == 1) {
201 markup(O, Markup::Immediate) << "min";
202 } else if (Imm == 30) {
203 markup(O, Markup::Immediate) << "inf";
204 } else if (Imm == 31) {
205 markup(O, Markup::Immediate) << "nan";
206 } else {
207 float FPVal = RISCVLoadFPImm::getFPImm(Imm);
208 // If the value is an integer, print a .0 fraction. Otherwise, use %g to
209 // which will not print trailing zeros and will use scientific notation
210 // if it is shorter than printing as a decimal. The smallest value requires
211 // 12 digits of precision including the decimal.
212 if (FPVal == (int)(FPVal))
213 markup(O, Markup::Immediate) << format("%.1f", FPVal);
214 else
215 markup(O, Markup::Immediate) << format("%.12g", FPVal);
216 }
217}
218
220 const MCSubtargetInfo &STI,
221 raw_ostream &O) {
222 const MCOperand &MO = MI->getOperand(OpNo);
223
224 assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands");
225 O << "(";
226 printRegName(O, MO.getReg());
227 O << ")";
228}
229
230void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
231 const MCSubtargetInfo &STI, raw_ostream &O) {
232 unsigned Imm = MI->getOperand(OpNo).getImm();
233 // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx,
234 // altfmt=1 without sew=8 or sew=16, or non-zero in bits 9 and above.
235 if (!RISCVVType::isValidVType(Imm) || (Imm >> 9) != 0) {
236 O << formatImm(Imm);
237 return;
238 }
239 // Print the text form.
241}
242
243void RISCVInstPrinter::printXSfmmVType(const MCInst *MI, unsigned OpNo,
244 const MCSubtargetInfo &STI,
245 raw_ostream &O) {
246 unsigned Imm = MI->getOperand(OpNo).getImm();
248 unsigned SEW = RISCVVType::getSEW(Imm);
249 O << "e" << SEW;
250 bool AltFmt = RISCVVType::isAltFmt(Imm);
251 if (AltFmt)
252 O << "alt";
254 O << ", w" << Widen;
255}
256
257// Print a Zcmp RList. If we are printing architectural register names rather
258// than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all
259// registers. Otherwise, we print "{ra, s0-s11}".
260void RISCVInstPrinter::printRegList(const MCInst *MI, unsigned OpNo,
261 const MCSubtargetInfo &STI, raw_ostream &O) {
262 unsigned Imm = MI->getOperand(OpNo).getImm();
263
265 Imm <= RISCVZC::RLISTENCODE::RA_S0_S11 && "Invalid Rlist");
266
267 O << "{";
268 printRegName(O, RISCV::X1);
269
271 O << ", ";
272 printRegName(O, RISCV::X8);
273 }
274
276 O << '-';
278 printRegName(O, RISCV::X9);
279 }
280
282 if (ArchRegNames)
283 O << ", ";
285 printRegName(O, RISCV::X18);
286 }
287
289 if (ArchRegNames)
290 O << '-';
292 // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we
293 // must skip to S11(X27).
295 ++Offset;
296 printRegName(O, RISCV::X19 + Offset);
297 }
298
299 O << "}";
300}
301
302void RISCVInstPrinter::printRegReg(const MCInst *MI, unsigned OpNo,
303 const MCSubtargetInfo &STI, raw_ostream &O) {
304 const MCOperand &OffsetMO = MI->getOperand(OpNo + 1);
305
306 assert(OffsetMO.isReg() && "printRegReg can only print register operands");
307 printRegName(O, OffsetMO.getReg());
308
309 O << "(";
310 const MCOperand &BaseMO = MI->getOperand(OpNo);
311 assert(BaseMO.isReg() && "printRegReg can only print register operands");
312 printRegName(O, BaseMO.getReg());
313 O << ")";
314}
315
316void RISCVInstPrinter::printStackAdj(const MCInst *MI, unsigned OpNo,
317 const MCSubtargetInfo &STI, raw_ostream &O,
318 bool Negate) {
319 int64_t Imm = MI->getOperand(OpNo).getImm();
320 bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
321 int64_t StackAdj = 0;
322 auto RlistVal = MI->getOperand(0).getImm();
323 auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64);
324 StackAdj = Imm + Base;
325 assert((StackAdj >= Base && StackAdj <= Base + 48) &&
326 "Incorrect stack adjust");
327 if (Negate)
328 StackAdj = -StackAdj;
329
330 // RAII guard for ANSI color escape sequences
331 WithMarkup ScopedMarkup = markup(O, Markup::Immediate);
332 O << StackAdj;
333}
334
335void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo,
336 const MCSubtargetInfo &STI,
337 raw_ostream &O) {
338 const MCOperand &MO = MI->getOperand(OpNo);
339
340 assert(MO.isReg() && "printVMaskReg can only print register operands");
341 if (MO.getReg() == RISCV::NoRegister)
342 return;
343 O << ", ";
344 printRegName(O, MO.getReg());
345 O << ".t";
346}
347
348void RISCVInstPrinter::printVScaleReg(const MCInst *MI, unsigned OpNo,
349 const MCSubtargetInfo &STI,
350 raw_ostream &O) {
351 const MCOperand &MO = MI->getOperand(OpNo);
352
353 assert(MO.isReg() && "printVScaleReg can only print register operands");
354 O << ", ";
355 printRegName(O, MO.getReg());
356 O << ".scale";
357}
358
359void RISCVInstPrinter::printTileLambda(const MCInst *MI, unsigned OpNo,
360 const MCSubtargetInfo &STI,
361 raw_ostream &O) {
362 const MCOperand &MO = MI->getOperand(OpNo);
363
364 assert(MO.isImm() && "printTileLambda can only print immediate operands");
365 unsigned Lambda = MO.getImm();
366 if (Lambda == 0)
367 return;
368
369 assert(Lambda <= 7 && "Unexpected tile lambda encoding");
370 O << ", L" << (1U << (Lambda - 1));
371}
372
373void RISCVInstPrinter::printImm(const MCInst *MI, unsigned OpNo,
374 const MCSubtargetInfo &STI, raw_ostream &O) {
375 const MCOperand &Op = MI->getOperand(OpNo);
376 const unsigned Opcode = MI->getOpcode();
377 uint64_t Imm = Op.getImm();
379 (Opcode == RISCV::ANDI || Opcode == RISCV::ORI || Opcode == RISCV::XORI ||
380 Opcode == RISCV::C_ANDI || Opcode == RISCV::AUIPC ||
381 Opcode == RISCV::LUI)) {
382 if (!STI.hasFeature(RISCV::Feature64Bit))
383 Imm &= 0xffffffff;
385 } else
387}
388
390 // When PrintAliases is enabled, and EmitX8AsFP is enabled, x8 will be printed
391 // as fp instead of s0. Note that these similar registers are not replaced:
392 // - X8_H: used for f16 register in zhinx
393 // - X8_W: used for f32 register in zfinx
394 // - X8_X9: used for GPR Pair
395 if (!ArchRegNames && (EmitX8AsFP || RISCVMCOptions::Global.emit_x8_as_fp) &&
396 Reg == RISCV::X8)
397 return "fp";
398 return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName
399 : RISCV::ABIRegAltName);
400}
static SDValue Widen(SelectionDAG *CurDAG, SDValue N)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
static cl::opt< bool > ArchRegNames("csky-arch-reg-names", cl::desc("Print architectural register names rather than the " "ABI names (such as r14 instead of sp)"), cl::init(false), cl::Hidden)
IRTranslator LLVM IR MI
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
static bool EmitX8AsFP
WithMarkup markup(raw_ostream &OS, Markup M)
format_object< int64_t > formatHex(int64_t Value) const
bool SymbolizeOperands
If true, symbolize branch target and memory reference operands.
void printAnnotation(raw_ostream &OS, StringRef Annot)
Utility function for printing annotations.
const MCAsmInfo & MAI
format_object< int64_t > formatImm(int64_t Value) const
Utility function to print immediates in decimal or hex.
bool PrintBranchImmAsAddress
If true, a branch immediate (e.g.
bool PrintAliases
True if we prefer aliases (e.g. nop) to raw mnemonics.
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
int64_t getImm() const
Definition MCInst.h:84
bool isImm() const
Definition MCInst.h:66
bool isReg() const
Definition MCInst.h:65
MCRegister getReg() const
Returns the register number.
Definition MCInst.h:73
const MCExpr * getExpr() const
Definition MCInst.h:118
bool isExpr() const
Definition MCInst.h:69
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
Generic base class for all target subtargets.
bool hasFeature(unsigned Feature) const
const Triple & getTargetTriple() const
const FeatureBitset & getFeatureBits() const
void printSMTVType(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printRegList(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printTileLambda(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
static const char * getRegisterName(MCRegister Reg)
void printCSRSystemRegister(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printXSfmmVType(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printImm(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printFenceArg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printVMaskReg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
bool applyTargetSpecificCLOption(StringRef Opt) override
Customize the printer according to a command line option.
void printFRMArgLegacy(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
bool printAliasInstr(const MCInst *MI, uint64_t Address, const MCSubtargetInfo &STI, raw_ostream &O)
void printRegReg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printFRMArg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &O) override
Print the specified MCInst to the specified raw_ostream.
void printFPImmOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printInstruction(const MCInst *MI, uint64_t Address, const MCSubtargetInfo &STI, raw_ostream &O)
void printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printRegName(raw_ostream &O, MCRegister Reg) override
Print the assembler register name.
void printVTypeI(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printVScaleReg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printStackAdj(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O, bool Negate=false)
void printBranchOperand(const MCInst *MI, uint64_t Address, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool isOSBinFormatMachO() const
Tests whether the environment is MachO.
Definition Triple.h:876
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
static StringRef roundingModeToString(RoundingMode RndMode)
float getFPImm(unsigned Imm)
bool uncompress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI)
static unsigned getXSfmmWiden(unsigned VType)
static bool isValidVType(unsigned VType)
LLVM_ABI void printVType(unsigned VType, raw_ostream &OS)
static bool isValidXSfmmVType(unsigned VTypeI)
static bool isAltFmt(unsigned VType)
static unsigned getSEW(unsigned VType)
static unsigned getStackAdjBase(unsigned RlistVal, bool IsRV64)
static StringRef SMTVTypeModeToString(SMTVTypeMode TypeMode)
static bool isValidSMTVTypeMode(unsigned Mode)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:102
DWARFExpression::Operation Op