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"
19#include "llvm/MC/MCInstPrinter.h"
20#include "llvm/MC/MCInstrAnalysis.h"
21#include "llvm/MC/MCSubtargetInfo.h"
22#include "llvm/MC/MCSymbol.h"
23#include "llvm/Support/ErrorHandling.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.
44bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt) {
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
62void RISCVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
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(OutInst&: UncompressedMI, MI: *MI, STI);
70 if (Res)
71 NewMI = &UncompressedMI;
72 if (!PrintAliases || CLOpts.no_aliases ||
73 !printAliasInstr(MI: NewMI, Address, STI, OS&: O))
74 printInstruction(MI: NewMI, Address, STI, O);
75 printAnnotation(OS&: O, Annot);
76}
77
78void RISCVInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) {
79 markup(OS&: O, M: Markup::Register) << getRegisterName(Reg);
80}
81
82void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
83 const MCSubtargetInfo &STI,
84 raw_ostream &O) {
85 const MCOperand &MO = MI->getOperand(i: OpNo);
86
87 if (MO.isReg()) {
88 printRegName(O, Reg: 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
101void RISCVInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address,
102 unsigned OpNo,
103 const MCSubtargetInfo &STI,
104 raw_ostream &O) {
105 // Do not print the numeric target address when symbolizing.
106 if (SymbolizeOperands)
107 return;
108
109 const MCOperand &MO = MI->getOperand(i: OpNo);
110 if (!MO.isImm())
111 return printOperand(MI, OpNo, STI, O);
112
113 if (PrintBranchImmAsAddress) {
114 uint64_t Target = Address + MO.getImm();
115 if (!STI.hasFeature(Feature: RISCV::Feature64Bit))
116 Target &= 0xffffffff;
117 markup(OS&: O, M: Markup::Target) << formatHex(Value: Target);
118 } else {
119 markup(OS&: O, M: Markup::Target) << formatImm(Value: MO.getImm());
120 }
121}
122
123void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo,
124 const MCSubtargetInfo &STI,
125 raw_ostream &O) {
126 unsigned Imm = MI->getOperand(i: OpNo).getImm();
127 auto Range = RISCVSysReg::lookupSysRegByEncoding(Encoding: Imm);
128 bool PreferFeatureSpecific = llvm::any_of(Range, P: [&](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(ActiveFeatures: STI.getFeatureBits()) &&
137 (!PreferFeatureSpecific || Reg.FeaturesRequired.any())) {
138 markup(OS&: O, M: Markup::Register) << RISCVSysReg::getSysRegStr(Reg.Name);
139 return;
140 }
141 }
142 markup(OS&: O, M: Markup::Register) << formatImm(Value: Imm);
143}
144
145void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
146 const MCSubtargetInfo &STI,
147 raw_ostream &O) {
148 unsigned FenceArg = MI->getOperand(i: 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(i: OpNo).getImm());
168 assert(XSMTVTypeMode::isValidSMTVTypeMode(VType) &&
169 "SpacemiT's Integer Matrix only supports [i4|i8] mode");
170 O << ", " << XSMTVTypeMode::SMTVTypeModeToString(TypeMode: 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(i: OpNo).getImm());
177 if (PrintAliases && !CLOpts.no_aliases &&
178 FRMArg == RISCVFPRndMode::RoundingMode::DYN)
179 return;
180 O << ", " << RISCVFPRndMode::roundingModeToString(RndMode: FRMArg);
181}
182
183void RISCVInstPrinter::printFRMArgLegacy(const MCInst *MI, unsigned OpNo,
184 const MCSubtargetInfo &STI,
185 raw_ostream &O) {
186 auto FRMArg =
187 static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(i: 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.
191 if (FRMArg == RISCVFPRndMode::RoundingMode::RNE)
192 return;
193 O << ", " << RISCVFPRndMode::roundingModeToString(RndMode: FRMArg);
194}
195
196void RISCVInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNo,
197 const MCSubtargetInfo &STI,
198 raw_ostream &O) {
199 unsigned Imm = MI->getOperand(i: OpNo).getImm();
200 if (Imm == 1) {
201 markup(OS&: O, M: Markup::Immediate) << "min";
202 } else if (Imm == 30) {
203 markup(OS&: O, M: Markup::Immediate) << "inf";
204 } else if (Imm == 31) {
205 markup(OS&: O, M: 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(OS&: O, M: Markup::Immediate) << format(Fmt: "%.1f", Vals: FPVal);
214 else
215 markup(OS&: O, M: Markup::Immediate) << format(Fmt: "%.12g", Vals: FPVal);
216 }
217}
218
219void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo,
220 const MCSubtargetInfo &STI,
221 raw_ostream &O) {
222 const MCOperand &MO = MI->getOperand(i: OpNo);
223
224 assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands");
225 O << "(";
226 printRegName(O, Reg: 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(i: 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(VType: Imm) || (Imm >> 9) != 0) {
236 O << formatImm(Value: Imm);
237 return;
238 }
239 // Print the text form.
240 RISCVVType::printVType(VType: Imm, OS&: O);
241}
242
243void RISCVInstPrinter::printXSfmmVType(const MCInst *MI, unsigned OpNo,
244 const MCSubtargetInfo &STI,
245 raw_ostream &O) {
246 unsigned Imm = MI->getOperand(i: OpNo).getImm();
247 assert(RISCVVType::isValidXSfmmVType(Imm));
248 unsigned SEW = RISCVVType::getSEW(VType: Imm);
249 O << "e" << SEW;
250 bool AltFmt = RISCVVType::isAltFmt(VType: Imm);
251 if (AltFmt)
252 O << "alt";
253 unsigned Widen = RISCVVType::getXSfmmWiden(VType: Imm);
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(i: OpNo).getImm();
263
264 assert(Imm >= RISCVZC::RLISTENCODE::RA &&
265 Imm <= RISCVZC::RLISTENCODE::RA_S0_S11 && "Invalid Rlist");
266
267 O << "{";
268 printRegName(O, Reg: RISCV::X1);
269
270 if (Imm >= RISCVZC::RLISTENCODE::RA_S0) {
271 O << ", ";
272 printRegName(O, Reg: RISCV::X8);
273 }
274
275 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S1) {
276 O << '-';
277 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S1 || ArchRegNames)
278 printRegName(O, Reg: RISCV::X9);
279 }
280
281 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S2) {
282 if (ArchRegNames)
283 O << ", ";
284 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S2 || ArchRegNames)
285 printRegName(O, Reg: RISCV::X18);
286 }
287
288 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S3) {
289 if (ArchRegNames)
290 O << '-';
291 unsigned Offset = (Imm - RISCVZC::RLISTENCODE::RA_S0_S3);
292 // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we
293 // must skip to S11(X27).
294 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S11)
295 ++Offset;
296 printRegName(O, Reg: 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(i: OpNo + 1);
305
306 assert(OffsetMO.isReg() && "printRegReg can only print register operands");
307 printRegName(O, Reg: OffsetMO.getReg());
308
309 O << "(";
310 const MCOperand &BaseMO = MI->getOperand(i: OpNo);
311 assert(BaseMO.isReg() && "printRegReg can only print register operands");
312 printRegName(O, Reg: 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(i: OpNo).getImm();
320 bool IsRV64 = STI.hasFeature(Feature: RISCV::Feature64Bit);
321 int64_t StackAdj = 0;
322 auto RlistVal = MI->getOperand(i: 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(OS&: O, M: 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(i: 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, Reg: 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(i: OpNo);
352
353 assert(MO.isReg() && "printVScaleReg can only print register operands");
354 O << ", ";
355 printRegName(O, Reg: 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(i: 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(i: OpNo);
376 const unsigned Opcode = MI->getOpcode();
377 uint64_t Imm = Op.getImm();
378 if (STI.getTargetTriple().isOSBinFormatMachO() &&
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(Feature: RISCV::Feature64Bit))
383 Imm &= 0xffffffff;
384 markup(OS&: O, M: Markup::Immediate) << formatHex(Value: Imm);
385 } else
386 markup(OS&: O, M: Markup::Immediate) << formatImm(Value: Imm);
387}
388
389const char *RISCVInstPrinter::getRegisterName(MCRegister Reg) {
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, AltIdx: ArchRegNames ? RISCV::NoRegAltName
399 : RISCV::ABIRegAltName);
400}
401