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
40 const MCRegisterInfo &MRI)
42 CLOpts(RISCV_MC::getCLOpts(MAI.getTargetOptions())) {}
43
44// -riscv-no-aliases and -riscv-emit-x8-as-fp are used by llvm-mc and llc. They
45// can be used by `llvm-objdump`, but we override their values here to handle
46// options passed to `llvm-objdump` with `-M` (which matches GNU objdump). There
47// did not seem to be an easier way to allow these options in all these tools,
48// without doing it this way.
50 if (Opt == "no-aliases") {
51 PrintAliases = false;
52 return true;
53 }
54 if (Opt == "numeric") {
55 ArchRegNames = true;
56 return true;
57 }
58 if (Opt == "emit-x8-as-fp") {
59 if (!ArchRegNames)
60 EmitX8AsFP = true;
61 return true;
62 }
63
64 return false;
65}
66
68 StringRef Annot, const MCSubtargetInfo &STI,
69 raw_ostream &O) {
70 bool Res = false;
71 const MCInst *NewMI = MI;
72 MCInst UncompressedMI;
73 if (PrintAliases && !CLOpts.no_aliases)
74 Res = RISCVRVC::uncompress(UncompressedMI, *MI, STI);
75 if (Res)
76 NewMI = &UncompressedMI;
77 if (!PrintAliases || CLOpts.no_aliases ||
78 !printAliasInstr(NewMI, Address, STI, O))
79 printInstruction(NewMI, Address, STI, O);
80 printAnnotation(O, Annot);
81}
82
86
87void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
88 const MCSubtargetInfo &STI,
89 raw_ostream &O) {
90 const MCOperand &MO = MI->getOperand(OpNo);
91
92 if (MO.isReg()) {
93 printRegName(O, MO.getReg());
94 return;
95 }
96
97 if (MO.isImm()) {
98 printImm(MI, OpNo, STI, O);
99 return;
100 }
101
102 assert(MO.isExpr() && "Unknown operand kind in printOperand");
103 MAI.printExpr(O, *MO.getExpr());
104}
105
107 unsigned OpNo,
108 const MCSubtargetInfo &STI,
109 raw_ostream &O) {
110 // Do not print the numeric target address when symbolizing.
112 return;
113
114 const MCOperand &MO = MI->getOperand(OpNo);
115 if (!MO.isImm())
116 return printOperand(MI, OpNo, STI, O);
117
119 uint64_t Target = Address + MO.getImm();
120 if (!STI.hasFeature(RISCV::Feature64Bit))
121 Target &= 0xffffffff;
123 } else {
125 }
126}
127
129 const MCSubtargetInfo &STI,
130 raw_ostream &O) {
131 unsigned Imm = MI->getOperand(OpNo).getImm();
132 auto Range = RISCVSysReg::lookupSysRegByEncoding(Imm);
133 bool PreferFeatureSpecific = llvm::any_of(Range, [&](const auto &Reg) {
134 return !Reg.IsAltName && !Reg.IsDeprecatedName &&
135 Reg.FeaturesRequired.any() &&
136 Reg.haveRequiredFeatures(STI.getFeatureBits());
137 });
138 for (auto &Reg : Range) {
139 if (Reg.IsAltName || Reg.IsDeprecatedName)
140 continue;
141 if (Reg.haveRequiredFeatures(STI.getFeatureBits()) &&
142 (!PreferFeatureSpecific || Reg.FeaturesRequired.any())) {
143 markup(O, Markup::Register) << RISCVSysReg::getSysRegStr(Reg.Name);
144 return;
145 }
146 }
148}
149
150void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
151 const MCSubtargetInfo &STI,
152 raw_ostream &O) {
153 unsigned FenceArg = MI->getOperand(OpNo).getImm();
154 assert (((FenceArg >> 4) == 0) && "Invalid immediate in printFenceArg");
155
156 if ((FenceArg & RISCVFenceField::I) != 0)
157 O << 'i';
158 if ((FenceArg & RISCVFenceField::O) != 0)
159 O << 'o';
160 if ((FenceArg & RISCVFenceField::R) != 0)
161 O << 'r';
162 if ((FenceArg & RISCVFenceField::W) != 0)
163 O << 'w';
164 if (FenceArg == 0)
165 O << "0";
166}
167
168void RISCVInstPrinter::printSMTVType(const MCInst *MI, unsigned OpNo,
169 const MCSubtargetInfo &STI,
170 raw_ostream &O) {
171 auto VType =
172 static_cast<XSMTVTypeMode::SMTVTypeMode>(MI->getOperand(OpNo).getImm());
174 "SpacemiT's Integer Matrix only supports [i4|i8] mode");
175 O << ", " << XSMTVTypeMode::SMTVTypeModeToString(VType);
176}
177
178void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo,
179 const MCSubtargetInfo &STI, raw_ostream &O) {
180 auto FRMArg =
181 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
182 if (PrintAliases && !CLOpts.no_aliases &&
184 return;
185 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
186}
187
189 const MCSubtargetInfo &STI,
190 raw_ostream &O) {
191 auto FRMArg =
192 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
193 // Never print rounding mode if it's the default 'rne'. This ensures the
194 // output can still be parsed by older tools that erroneously failed to
195 // accept a rounding mode.
197 return;
198 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
199}
200
202 const MCSubtargetInfo &STI,
203 raw_ostream &O) {
204 unsigned Imm = MI->getOperand(OpNo).getImm();
205 if (Imm == 1) {
206 markup(O, Markup::Immediate) << "min";
207 } else if (Imm == 30) {
208 markup(O, Markup::Immediate) << "inf";
209 } else if (Imm == 31) {
210 markup(O, Markup::Immediate) << "nan";
211 } else {
212 float FPVal = RISCVLoadFPImm::getFPImm(Imm);
213 // If the value is an integer, print a .0 fraction. Otherwise, use %g to
214 // which will not print trailing zeros and will use scientific notation
215 // if it is shorter than printing as a decimal. The smallest value requires
216 // 12 digits of precision including the decimal.
217 if (FPVal == (int)(FPVal))
218 markup(O, Markup::Immediate) << format("%.1f", FPVal);
219 else
220 markup(O, Markup::Immediate) << format("%.12g", FPVal);
221 }
222}
223
225 const MCSubtargetInfo &STI,
226 raw_ostream &O) {
227 const MCOperand &MO = MI->getOperand(OpNo);
228
229 assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands");
230 O << "(";
231 printRegName(O, MO.getReg());
232 O << ")";
233}
234
235void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
236 const MCSubtargetInfo &STI, raw_ostream &O) {
237 unsigned Imm = MI->getOperand(OpNo).getImm();
238 // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx,
239 // altfmt=1 without sew=8 or sew=16, or non-zero in bits 9 and above.
240 if (!RISCVVType::isValidVType(Imm) || (Imm >> 9) != 0) {
241 O << formatImm(Imm);
242 return;
243 }
244 // Print the text form.
246}
247
248void RISCVInstPrinter::printXSfmmVType(const MCInst *MI, unsigned OpNo,
249 const MCSubtargetInfo &STI,
250 raw_ostream &O) {
251 unsigned Imm = MI->getOperand(OpNo).getImm();
253 unsigned SEW = RISCVVType::getSEW(Imm);
254 O << "e" << SEW;
255 bool AltFmt = RISCVVType::isAltFmt(Imm);
256 if (AltFmt)
257 O << "alt";
259 O << ", w" << Widen;
260}
261
262// Print a Zcmp RList. If we are printing architectural register names rather
263// than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all
264// registers. Otherwise, we print "{ra, s0-s11}".
265void RISCVInstPrinter::printRegList(const MCInst *MI, unsigned OpNo,
266 const MCSubtargetInfo &STI, raw_ostream &O) {
267 unsigned Imm = MI->getOperand(OpNo).getImm();
268
270 Imm <= RISCVZC::RLISTENCODE::RA_S0_S11 && "Invalid Rlist");
271
272 O << "{";
273 printRegName(O, RISCV::X1);
274
276 O << ", ";
277 printRegName(O, RISCV::X8);
278 }
279
281 O << '-';
283 printRegName(O, RISCV::X9);
284 }
285
287 if (ArchRegNames)
288 O << ", ";
290 printRegName(O, RISCV::X18);
291 }
292
294 if (ArchRegNames)
295 O << '-';
297 // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we
298 // must skip to S11(X27).
300 ++Offset;
301 printRegName(O, RISCV::X19 + Offset);
302 }
303
304 O << "}";
305}
306
307void RISCVInstPrinter::printRegReg(const MCInst *MI, unsigned OpNo,
308 const MCSubtargetInfo &STI, raw_ostream &O) {
309 const MCOperand &OffsetMO = MI->getOperand(OpNo + 1);
310
311 assert(OffsetMO.isReg() && "printRegReg can only print register operands");
312 printRegName(O, OffsetMO.getReg());
313
314 O << "(";
315 const MCOperand &BaseMO = MI->getOperand(OpNo);
316 assert(BaseMO.isReg() && "printRegReg can only print register operands");
317 printRegName(O, BaseMO.getReg());
318 O << ")";
319}
320
321void RISCVInstPrinter::printStackAdj(const MCInst *MI, unsigned OpNo,
322 const MCSubtargetInfo &STI, raw_ostream &O,
323 bool Negate) {
324 int64_t Imm = MI->getOperand(OpNo).getImm();
325 bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
326 int64_t StackAdj = 0;
327 auto RlistVal = MI->getOperand(0).getImm();
328 auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64);
329 StackAdj = Imm + Base;
330 assert((StackAdj >= Base && StackAdj <= Base + 48) &&
331 "Incorrect stack adjust");
332 if (Negate)
333 StackAdj = -StackAdj;
334
335 // RAII guard for ANSI color escape sequences
336 WithMarkup ScopedMarkup = markup(O, Markup::Immediate);
337 O << StackAdj;
338}
339
340void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo,
341 const MCSubtargetInfo &STI,
342 raw_ostream &O) {
343 const MCOperand &MO = MI->getOperand(OpNo);
344
345 assert(MO.isReg() && "printVMaskReg can only print register operands");
346 if (MO.getReg() == RISCV::NoRegister)
347 return;
348 O << ", ";
349 printRegName(O, MO.getReg());
350 O << ".t";
351}
352
353void RISCVInstPrinter::printVScaleReg(const MCInst *MI, unsigned OpNo,
354 const MCSubtargetInfo &STI,
355 raw_ostream &O) {
356 const MCOperand &MO = MI->getOperand(OpNo);
357
358 assert(MO.isReg() && "printVScaleReg can only print register operands");
359 O << ", ";
360 printRegName(O, MO.getReg());
361 O << ".scale";
362}
363
364void RISCVInstPrinter::printTileLambda(const MCInst *MI, unsigned OpNo,
365 const MCSubtargetInfo &STI,
366 raw_ostream &O) {
367 const MCOperand &MO = MI->getOperand(OpNo);
368
369 assert(MO.isImm() && "printTileLambda can only print immediate operands");
370 unsigned Lambda = MO.getImm();
371 if (Lambda == 0)
372 return;
373
374 assert(Lambda <= 7 && "Unexpected tile lambda encoding");
375 O << ", L" << (1U << (Lambda - 1));
376}
377
378void RISCVInstPrinter::printImm(const MCInst *MI, unsigned OpNo,
379 const MCSubtargetInfo &STI, raw_ostream &O) {
380 const MCOperand &Op = MI->getOperand(OpNo);
381 const unsigned Opcode = MI->getOpcode();
382 uint64_t Imm = Op.getImm();
384 (Opcode == RISCV::ANDI || Opcode == RISCV::ORI || Opcode == RISCV::XORI ||
385 Opcode == RISCV::C_ANDI || Opcode == RISCV::AUIPC ||
386 Opcode == RISCV::LUI)) {
387 if (!STI.hasFeature(RISCV::Feature64Bit))
388 Imm &= 0xffffffff;
390 } else
392}
393
394const char *RISCVInstPrinter::getRegisterName(const RISCVMCOptions &CLOpts,
395 MCRegister Reg) {
396 // When PrintAliases is enabled, and EmitX8AsFP is enabled, x8 will be printed
397 // as fp instead of s0. Note that these similar registers are not replaced:
398 // - X8_H: used for f16 register in zhinx
399 // - X8_W: used for f32 register in zfinx
400 // - X8_X9: used for GPR Pair
401 if (!ArchRegNames && (EmitX8AsFP || CLOpts.emit_x8_as_fp) && Reg == RISCV::X8)
402 return "fp";
403 return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName
404 : RISCV::ABIRegAltName);
405}
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
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition MCAsmInfo.h:67
WithMarkup markup(raw_ostream &OS, Markup M)
format_object< int64_t > formatHex(int64_t Value) const
const MCInstrInfo & MII
bool SymbolizeOperands
If true, symbolize branch target and memory reference operands.
const MCRegisterInfo & MRI
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.
MCInstPrinter(const MCAsmInfo &mai, const MCInstrInfo &mii, const MCRegisterInfo &mri)
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
Interface to description of machine instruction set.
Definition MCInstrInfo.h:27
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
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
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)
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)
static const char * getRegisterName(const RISCVMCOptions &CLOpts, MCRegister Reg)
RISCVInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI)
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