1 //===-- RISCVInstPrinter.cpp - Convert RISC-V MCInst to asm syntax --------===//
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
7 //===----------------------------------------------------------------------===//
9 // This class prints an RISC-V MCInst to a .s file.
11 //===----------------------------------------------------------------------===//
13 #include "RISCVInstPrinter.h"
14 #include "RISCVBaseInfo.h"
15 #include "RISCVMCExpr.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/MCRegisterInfo.h"
21 #include "llvm/MC/MCSubtargetInfo.h"
22 #include "llvm/MC/MCSymbol.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/FormattedStream.h"
28 #define DEBUG_TYPE "asm-printer"
30 // Include the auto-generated portion of the assembly writer.
31 #define PRINT_ALIAS_INSTR
32 #include "RISCVGenAsmWriter.inc"
35 NoAliases("riscv-no-aliases",
36 cl::desc("Disable the emission of assembler pseudo instructions"),
37 cl::init(false), cl::Hidden
);
39 // Print architectural register names rather than the ABI names (such as x2
41 // TODO: Make RISCVInstPrinter::getRegisterName non-static so that this can a
43 static bool ArchRegNames
;
45 // The command-line flags above are used by llvm-mc and llc. They can be used by
46 // `llvm-objdump`, but we override their values here to handle options passed to
47 // `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to
48 // be an easier way to allow these options in all these tools, without doing it
50 bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt
) {
51 if (Opt
== "no-aliases") {
55 if (Opt
== "numeric") {
63 void RISCVInstPrinter::printInst(const MCInst
*MI
, uint64_t Address
,
64 StringRef Annot
, const MCSubtargetInfo
&STI
,
67 const MCInst
*NewMI
= MI
;
68 MCInst UncompressedMI
;
69 if (PrintAliases
&& !NoAliases
)
70 Res
= RISCVRVC::uncompress(UncompressedMI
, *MI
, STI
);
72 NewMI
= const_cast<MCInst
*>(&UncompressedMI
);
73 if (!PrintAliases
|| NoAliases
|| !printAliasInstr(NewMI
, Address
, STI
, O
))
74 printInstruction(NewMI
, Address
, STI
, O
);
75 printAnnotation(O
, Annot
);
78 void RISCVInstPrinter::printRegName(raw_ostream
&O
, MCRegister Reg
) const {
79 markup(O
, Markup::Register
) << getRegisterName(Reg
);
82 void RISCVInstPrinter::printOperand(const MCInst
*MI
, unsigned OpNo
,
83 const MCSubtargetInfo
&STI
, raw_ostream
&O
,
84 const char *Modifier
) {
85 assert((Modifier
== nullptr || Modifier
[0] == 0) && "No modifiers supported");
86 const MCOperand
&MO
= MI
->getOperand(OpNo
);
89 printRegName(O
, MO
.getReg());
94 markup(O
, Markup::Immediate
) << formatImm(MO
.getImm());
98 assert(MO
.isExpr() && "Unknown operand kind in printOperand");
99 MO
.getExpr()->print(O
, &MAI
);
102 void RISCVInstPrinter::printBranchOperand(const MCInst
*MI
, uint64_t Address
,
104 const MCSubtargetInfo
&STI
,
106 const MCOperand
&MO
= MI
->getOperand(OpNo
);
108 return printOperand(MI
, OpNo
, STI
, O
);
110 if (PrintBranchImmAsAddress
) {
111 uint64_t Target
= Address
+ MO
.getImm();
112 if (!STI
.hasFeature(RISCV::Feature64Bit
))
113 Target
&= 0xffffffff;
114 markup(O
, Markup::Target
) << formatHex(Target
);
116 markup(O
, Markup::Target
) << formatImm(MO
.getImm());
120 void RISCVInstPrinter::printCSRSystemRegister(const MCInst
*MI
, unsigned OpNo
,
121 const MCSubtargetInfo
&STI
,
123 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
124 auto SysReg
= RISCVSysReg::lookupSysRegByEncoding(Imm
);
125 if (SysReg
&& SysReg
->haveRequiredFeatures(STI
.getFeatureBits()))
126 markup(O
, Markup::Register
) << SysReg
->Name
;
128 markup(O
, Markup::Register
) << formatImm(Imm
);
131 void RISCVInstPrinter::printFenceArg(const MCInst
*MI
, unsigned OpNo
,
132 const MCSubtargetInfo
&STI
,
134 unsigned FenceArg
= MI
->getOperand(OpNo
).getImm();
135 assert (((FenceArg
>> 4) == 0) && "Invalid immediate in printFenceArg");
137 if ((FenceArg
& RISCVFenceField::I
) != 0)
139 if ((FenceArg
& RISCVFenceField::O
) != 0)
141 if ((FenceArg
& RISCVFenceField::R
) != 0)
143 if ((FenceArg
& RISCVFenceField::W
) != 0)
149 void RISCVInstPrinter::printFRMArg(const MCInst
*MI
, unsigned OpNo
,
150 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
152 static_cast<RISCVFPRndMode::RoundingMode
>(MI
->getOperand(OpNo
).getImm());
153 if (PrintAliases
&& !NoAliases
&& FRMArg
== RISCVFPRndMode::RoundingMode::DYN
)
155 O
<< ", " << RISCVFPRndMode::roundingModeToString(FRMArg
);
158 void RISCVInstPrinter::printFRMArgLegacy(const MCInst
*MI
, unsigned OpNo
,
159 const MCSubtargetInfo
&STI
,
162 static_cast<RISCVFPRndMode::RoundingMode
>(MI
->getOperand(OpNo
).getImm());
163 // Never print rounding mode if it's the default 'rne'. This ensures the
164 // output can still be parsed by older tools that erroneously failed to
165 // accept a rounding mode.
166 if (FRMArg
== RISCVFPRndMode::RoundingMode::RNE
)
168 O
<< ", " << RISCVFPRndMode::roundingModeToString(FRMArg
);
171 void RISCVInstPrinter::printFPImmOperand(const MCInst
*MI
, unsigned OpNo
,
172 const MCSubtargetInfo
&STI
,
174 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
176 markup(O
, Markup::Immediate
) << "min";
177 } else if (Imm
== 30) {
178 markup(O
, Markup::Immediate
) << "inf";
179 } else if (Imm
== 31) {
180 markup(O
, Markup::Immediate
) << "nan";
182 float FPVal
= RISCVLoadFPImm::getFPImm(Imm
);
183 // If the value is an integer, print a .0 fraction. Otherwise, use %g to
184 // which will not print trailing zeros and will use scientific notation
185 // if it is shorter than printing as a decimal. The smallest value requires
186 // 12 digits of precision including the decimal.
187 if (FPVal
== (int)(FPVal
))
188 markup(O
, Markup::Immediate
) << format("%.1f", FPVal
);
190 markup(O
, Markup::Immediate
) << format("%.12g", FPVal
);
194 void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst
*MI
, unsigned OpNo
,
195 const MCSubtargetInfo
&STI
,
197 const MCOperand
&MO
= MI
->getOperand(OpNo
);
199 assert(MO
.isReg() && "printZeroOffsetMemOp can only print register operands");
201 printRegName(O
, MO
.getReg());
205 void RISCVInstPrinter::printVTypeI(const MCInst
*MI
, unsigned OpNo
,
206 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
207 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
208 // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx,
209 // or non-zero in bits 8 and above.
210 if (RISCVVType::getVLMUL(Imm
) == RISCVII::VLMUL::LMUL_RESERVED
||
211 RISCVVType::getSEW(Imm
) > 64 || (Imm
>> 8) != 0) {
215 // Print the text form.
216 RISCVVType::printVType(Imm
, O
);
219 void RISCVInstPrinter::printRlist(const MCInst
*MI
, unsigned OpNo
,
220 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
221 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
224 case RISCVZC::RLISTENCODE::RA
:
225 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
227 case RISCVZC::RLISTENCODE::RA_S0
:
228 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
230 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
232 case RISCVZC::RLISTENCODE::RA_S0_S1
:
233 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
235 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
237 markup(O
, Markup::Register
) << (ArchRegNames
? "x9" : "s1");
239 case RISCVZC::RLISTENCODE::RA_S0_S2
:
240 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
242 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
244 markup(O
, Markup::Register
) << (ArchRegNames
? "x9" : "s2");
247 markup(O
, Markup::Register
) << "x18";
250 case RISCVZC::RLISTENCODE::RA_S0_S3
:
251 case RISCVZC::RLISTENCODE::RA_S0_S4
:
252 case RISCVZC::RLISTENCODE::RA_S0_S5
:
253 case RISCVZC::RLISTENCODE::RA_S0_S6
:
254 case RISCVZC::RLISTENCODE::RA_S0_S7
:
255 case RISCVZC::RLISTENCODE::RA_S0_S8
:
256 case RISCVZC::RLISTENCODE::RA_S0_S9
:
257 case RISCVZC::RLISTENCODE::RA_S0_S11
:
258 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
260 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
263 markup(O
, Markup::Register
) << "x9";
265 markup(O
, Markup::Register
) << "x18";
268 markup(O
, Markup::Register
) << getRegisterName(
269 RISCV::X19
+ (Imm
== RISCVZC::RLISTENCODE::RA_S0_S11
271 : Imm
- RISCVZC::RLISTENCODE::RA_S0_S3
));
274 llvm_unreachable("invalid register list");
279 void RISCVInstPrinter::printRegReg(const MCInst
*MI
, unsigned OpNo
,
280 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
281 const MCOperand
&MO
= MI
->getOperand(OpNo
);
283 assert(MO
.isReg() && "printRegReg can only print register operands");
284 if (MO
.getReg() == RISCV::NoRegister
)
286 printRegName(O
, MO
.getReg());
289 const MCOperand
&MO1
= MI
->getOperand(OpNo
+ 1);
290 assert(MO1
.isReg() && "printRegReg can only print register operands");
291 printRegName(O
, MO1
.getReg());
295 void RISCVInstPrinter::printSpimm(const MCInst
*MI
, unsigned OpNo
,
296 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
297 int64_t Imm
= MI
->getOperand(OpNo
).getImm();
298 unsigned Opcode
= MI
->getOpcode();
299 bool IsRV64
= STI
.hasFeature(RISCV::Feature64Bit
);
300 bool IsEABI
= STI
.hasFeature(RISCV::FeatureRVE
);
302 auto RlistVal
= MI
->getOperand(0).getImm();
303 assert(RlistVal
!= 16 && "Incorrect rlist.");
304 auto Base
= RISCVZC::getStackAdjBase(RlistVal
, IsRV64
, IsEABI
);
306 assert((Spimm
>= Base
&& Spimm
<= Base
+ 48) && "Incorrect spimm");
307 if (Opcode
== RISCV::CM_PUSH
)
310 // RAII guard for ANSI color escape sequences
311 WithMarkup ScopedMarkup
= markup(O
, Markup::Immediate
);
312 RISCVZC::printSpimm(Spimm
, O
);
315 void RISCVInstPrinter::printVMaskReg(const MCInst
*MI
, unsigned OpNo
,
316 const MCSubtargetInfo
&STI
,
318 const MCOperand
&MO
= MI
->getOperand(OpNo
);
320 assert(MO
.isReg() && "printVMaskReg can only print register operands");
321 if (MO
.getReg() == RISCV::NoRegister
)
324 printRegName(O
, MO
.getReg());
328 const char *RISCVInstPrinter::getRegisterName(MCRegister Reg
) {
329 return getRegisterName(Reg
, ArchRegNames
? RISCV::NoRegAltName
330 : RISCV::ABIRegAltName
);