xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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