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 "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"
23 using namespace llvm;
24
25 #define DEBUG_TYPE "asm-printer"
26
27 // Include the auto-generated portion of the assembly writer.
28 #define PRINT_ALIAS_INSTR
29 #include "RISCVGenAsmWriter.inc"
30
31 static 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
36 static 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 x2
41 // instead of sp).
42 // TODO: Make RISCVInstPrinter::getRegisterName non-static so that this can a
43 // member.
44 static bool ArchRegNames;
45
46 // The command-line flags above are used by llvm-mc and llc. They can be used by
47 // `llvm-objdump`, but we override their values here to handle options passed to
48 // `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to
49 // be an easier way to allow these options in all these tools, without doing it
50 // this way.
applyTargetSpecificCLOption(StringRef Opt)51 bool 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
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)69 void 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 = const_cast<MCInst *>(&UncompressedMI);
79 if (!PrintAliases || NoAliases || !printAliasInstr(NewMI, Address, STI, O))
80 printInstruction(NewMI, Address, STI, O);
81 printAnnotation(O, Annot);
82 }
83
printRegName(raw_ostream & O,MCRegister Reg)84 void RISCVInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) {
85 markup(O, Markup::Register) << getRegisterName(Reg);
86 }
87
printOperand(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)88 void 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
printBranchOperand(const MCInst * MI,uint64_t Address,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)107 void 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
printCSRSystemRegister(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)125 void 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
printFenceArg(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)141 void 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
printFRMArg(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)159 void 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
printFRMArgLegacy(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)168 void 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 the
174 // output can still be parsed by older tools that erroneously failed to
175 // accept a rounding mode.
176 if (FRMArg == RISCVFPRndMode::RoundingMode::RNE)
177 return;
178 O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
179 }
180
printFPImmOperand(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)181 void 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 to
194 // which will not print trailing zeros and will use scientific notation
195 // if it is shorter than printing as a decimal. The smallest value requires
196 // 12 digits of precision including the decimal.
197 if (FPVal == (int)(FPVal))
198 markup(O, Markup::Immediate) << format("%.1f", FPVal);
199 else
200 markup(O, Markup::Immediate) << format("%.12g", FPVal);
201 }
202 }
203
printZeroOffsetMemOp(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)204 void 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
printVTypeI(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)215 void 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 // or non-zero in bits 8 and above.
220 if (RISCVVType::getVLMUL(Imm) == RISCVVType::VLMUL::LMUL_RESERVED ||
221 RISCVVType::getSEW(Imm) > 64 || (Imm >> 8) != 0) {
222 O << formatImm(Imm);
223 return;
224 }
225 // Print the text form.
226 RISCVVType::printVType(Imm, O);
227 }
228
printXSfmmVType(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)229 void RISCVInstPrinter::printXSfmmVType(const MCInst *MI, unsigned OpNo,
230 const MCSubtargetInfo &STI,
231 raw_ostream &O) {
232 unsigned Imm = MI->getOperand(OpNo).getImm();
233 assert(RISCVVType::isValidXSfmmVType(Imm));
234 unsigned SEW = RISCVVType::getSEW(Imm);
235 O << "e" << SEW;
236 bool AltFmt = RISCVVType::isAltFmt(Imm);
237 if (AltFmt)
238 O << "alt";
239 unsigned Widen = RISCVVType::getXSfmmWiden(Imm);
240 O << ", w" << Widen;
241 }
242
243 // Print a Zcmp RList. If we are printing architectural register names rather
244 // than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all
245 // registers. Otherwise, we print "{ra, s0-s11}".
printRegList(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)246 void RISCVInstPrinter::printRegList(const MCInst *MI, unsigned OpNo,
247 const MCSubtargetInfo &STI, raw_ostream &O) {
248 unsigned Imm = MI->getOperand(OpNo).getImm();
249
250 assert(Imm >= RISCVZC::RLISTENCODE::RA &&
251 Imm <= RISCVZC::RLISTENCODE::RA_S0_S11 && "Invalid Rlist");
252
253 O << "{";
254 printRegName(O, RISCV::X1);
255
256 if (Imm >= RISCVZC::RLISTENCODE::RA_S0) {
257 O << ", ";
258 printRegName(O, RISCV::X8);
259 }
260
261 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S1) {
262 O << '-';
263 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S1 || ArchRegNames)
264 printRegName(O, RISCV::X9);
265 }
266
267 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S2) {
268 if (ArchRegNames)
269 O << ", ";
270 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S2 || ArchRegNames)
271 printRegName(O, RISCV::X18);
272 }
273
274 if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S3) {
275 if (ArchRegNames)
276 O << '-';
277 unsigned Offset = (Imm - RISCVZC::RLISTENCODE::RA_S0_S3);
278 // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we
279 // must skip to S11(X27).
280 if (Imm == RISCVZC::RLISTENCODE::RA_S0_S11)
281 ++Offset;
282 printRegName(O, RISCV::X19 + Offset);
283 }
284
285 O << "}";
286 }
287
printRegReg(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)288 void RISCVInstPrinter::printRegReg(const MCInst *MI, unsigned OpNo,
289 const MCSubtargetInfo &STI, raw_ostream &O) {
290 const MCOperand &OffsetMO = MI->getOperand(OpNo + 1);
291
292 assert(OffsetMO.isReg() && "printRegReg can only print register operands");
293 printRegName(O, OffsetMO.getReg());
294
295 O << "(";
296 const MCOperand &BaseMO = MI->getOperand(OpNo);
297 assert(BaseMO.isReg() && "printRegReg can only print register operands");
298 printRegName(O, BaseMO.getReg());
299 O << ")";
300 }
301
printStackAdj(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O,bool Negate)302 void RISCVInstPrinter::printStackAdj(const MCInst *MI, unsigned OpNo,
303 const MCSubtargetInfo &STI, raw_ostream &O,
304 bool Negate) {
305 int64_t Imm = MI->getOperand(OpNo).getImm();
306 bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
307 int64_t StackAdj = 0;
308 auto RlistVal = MI->getOperand(0).getImm();
309 auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64);
310 StackAdj = Imm + Base;
311 assert((StackAdj >= Base && StackAdj <= Base + 48) &&
312 "Incorrect stack adjust");
313 if (Negate)
314 StackAdj = -StackAdj;
315
316 // RAII guard for ANSI color escape sequences
317 WithMarkup ScopedMarkup = markup(O, Markup::Immediate);
318 O << StackAdj;
319 }
320
printVMaskReg(const MCInst * MI,unsigned OpNo,const MCSubtargetInfo & STI,raw_ostream & O)321 void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo,
322 const MCSubtargetInfo &STI,
323 raw_ostream &O) {
324 const MCOperand &MO = MI->getOperand(OpNo);
325
326 assert(MO.isReg() && "printVMaskReg can only print register operands");
327 if (MO.getReg() == RISCV::NoRegister)
328 return;
329 O << ", ";
330 printRegName(O, MO.getReg());
331 O << ".t";
332 }
333
getRegisterName(MCRegister Reg)334 const char *RISCVInstPrinter::getRegisterName(MCRegister Reg) {
335 // When PrintAliases is enabled, and EmitX8AsFP is enabled, x8 will be printed
336 // as fp instead of s0. Note that these similar registers are not replaced:
337 // - X8_H: used for f16 register in zhinx
338 // - X8_W: used for f32 register in zfinx
339 // - X8_X9: used for GPR Pair
340 if (!ArchRegNames && EmitX8AsFP && Reg == RISCV::X8)
341 return "fp";
342 return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName
343 : RISCV::ABIRegAltName);
344 }
345