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
) << 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
) << MO
.getImm();
120 void RISCVInstPrinter::printCSRSystemRegister(const MCInst
*MI
, unsigned OpNo
,
121 const MCSubtargetInfo
&STI
,
123 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
124 auto SiFiveReg
= RISCVSysReg::lookupSiFiveRegByEncoding(Imm
);
125 auto SysReg
= RISCVSysReg::lookupSysRegByEncoding(Imm
);
126 if (SiFiveReg
&& SiFiveReg
->haveVendorRequiredFeatures(STI
.getFeatureBits()))
127 markup(O
, Markup::Register
) << SiFiveReg
->Name
;
128 else if (SysReg
&& SysReg
->haveRequiredFeatures(STI
.getFeatureBits()))
129 markup(O
, Markup::Register
) << SysReg
->Name
;
131 markup(O
, Markup::Register
) << Imm
;
134 void RISCVInstPrinter::printFenceArg(const MCInst
*MI
, unsigned OpNo
,
135 const MCSubtargetInfo
&STI
,
137 unsigned FenceArg
= MI
->getOperand(OpNo
).getImm();
138 assert (((FenceArg
>> 4) == 0) && "Invalid immediate in printFenceArg");
140 if ((FenceArg
& RISCVFenceField::I
) != 0)
142 if ((FenceArg
& RISCVFenceField::O
) != 0)
144 if ((FenceArg
& RISCVFenceField::R
) != 0)
146 if ((FenceArg
& RISCVFenceField::W
) != 0)
152 void RISCVInstPrinter::printFRMArg(const MCInst
*MI
, unsigned OpNo
,
153 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
155 static_cast<RISCVFPRndMode::RoundingMode
>(MI
->getOperand(OpNo
).getImm());
156 if (PrintAliases
&& !NoAliases
&& FRMArg
== RISCVFPRndMode::RoundingMode::DYN
)
158 O
<< ", " << RISCVFPRndMode::roundingModeToString(FRMArg
);
161 void RISCVInstPrinter::printFRMArgLegacy(const MCInst
*MI
, unsigned OpNo
,
162 const MCSubtargetInfo
&STI
,
165 static_cast<RISCVFPRndMode::RoundingMode
>(MI
->getOperand(OpNo
).getImm());
166 // Never print rounding mode if it's the default 'rne'. This ensures the
167 // output can still be parsed by older tools that erroneously failed to
168 // accept a rounding mode.
169 if (FRMArg
== RISCVFPRndMode::RoundingMode::RNE
)
171 O
<< ", " << RISCVFPRndMode::roundingModeToString(FRMArg
);
174 void RISCVInstPrinter::printFPImmOperand(const MCInst
*MI
, unsigned OpNo
,
175 const MCSubtargetInfo
&STI
,
177 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
179 markup(O
, Markup::Immediate
) << "min";
180 } else if (Imm
== 30) {
181 markup(O
, Markup::Immediate
) << "inf";
182 } else if (Imm
== 31) {
183 markup(O
, Markup::Immediate
) << "nan";
185 float FPVal
= RISCVLoadFPImm::getFPImm(Imm
);
186 // If the value is an integer, print a .0 fraction. Otherwise, use %g to
187 // which will not print trailing zeros and will use scientific notation
188 // if it is shorter than printing as a decimal. The smallest value requires
189 // 12 digits of precision including the decimal.
190 if (FPVal
== (int)(FPVal
))
191 markup(O
, Markup::Immediate
) << format("%.1f", FPVal
);
193 markup(O
, Markup::Immediate
) << format("%.12g", FPVal
);
197 void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst
*MI
, unsigned OpNo
,
198 const MCSubtargetInfo
&STI
,
200 const MCOperand
&MO
= MI
->getOperand(OpNo
);
202 assert(MO
.isReg() && "printZeroOffsetMemOp can only print register operands");
204 printRegName(O
, MO
.getReg());
208 void RISCVInstPrinter::printVTypeI(const MCInst
*MI
, unsigned OpNo
,
209 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
210 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
211 // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx,
212 // or non-zero in bits 8 and above.
213 if (RISCVVType::getVLMUL(Imm
) == RISCVII::VLMUL::LMUL_RESERVED
||
214 RISCVVType::getSEW(Imm
) > 64 || (Imm
>> 8) != 0) {
218 // Print the text form.
219 RISCVVType::printVType(Imm
, O
);
222 void RISCVInstPrinter::printRlist(const MCInst
*MI
, unsigned OpNo
,
223 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
224 unsigned Imm
= MI
->getOperand(OpNo
).getImm();
227 case RISCVZC::RLISTENCODE::RA
:
228 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
230 case RISCVZC::RLISTENCODE::RA_S0
:
231 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
233 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
235 case RISCVZC::RLISTENCODE::RA_S0_S1
:
236 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
238 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
240 markup(O
, Markup::Register
) << (ArchRegNames
? "x9" : "s1");
242 case RISCVZC::RLISTENCODE::RA_S0_S2
:
243 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
245 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
247 markup(O
, Markup::Register
) << (ArchRegNames
? "x9" : "s2");
250 markup(O
, Markup::Register
) << "x18";
253 case RISCVZC::RLISTENCODE::RA_S0_S3
:
254 case RISCVZC::RLISTENCODE::RA_S0_S4
:
255 case RISCVZC::RLISTENCODE::RA_S0_S5
:
256 case RISCVZC::RLISTENCODE::RA_S0_S6
:
257 case RISCVZC::RLISTENCODE::RA_S0_S7
:
258 case RISCVZC::RLISTENCODE::RA_S0_S8
:
259 case RISCVZC::RLISTENCODE::RA_S0_S9
:
260 case RISCVZC::RLISTENCODE::RA_S0_S11
:
261 markup(O
, Markup::Register
) << (ArchRegNames
? "x1" : "ra");
263 markup(O
, Markup::Register
) << (ArchRegNames
? "x8" : "s0");
266 markup(O
, Markup::Register
) << "x9";
268 markup(O
, Markup::Register
) << "x18";
271 markup(O
, Markup::Register
) << getRegisterName(
272 RISCV::X19
+ (Imm
== RISCVZC::RLISTENCODE::RA_S0_S11
274 : Imm
- RISCVZC::RLISTENCODE::RA_S0_S3
));
277 llvm_unreachable("invalid register list");
282 void RISCVInstPrinter::printSpimm(const MCInst
*MI
, unsigned OpNo
,
283 const MCSubtargetInfo
&STI
, raw_ostream
&O
) {
284 int64_t Imm
= MI
->getOperand(OpNo
).getImm();
285 unsigned Opcode
= MI
->getOpcode();
286 bool IsRV64
= STI
.hasFeature(RISCV::Feature64Bit
);
287 bool IsEABI
= STI
.hasFeature(RISCV::FeatureRVE
);
289 auto RlistVal
= MI
->getOperand(0).getImm();
290 assert(RlistVal
!= 16 && "Incorrect rlist.");
291 auto Base
= RISCVZC::getStackAdjBase(RlistVal
, IsRV64
, IsEABI
);
293 assert((Spimm
>= Base
&& Spimm
<= Base
+ 48) && "Incorrect spimm");
294 if (Opcode
== RISCV::CM_PUSH
)
297 // RAII guard for ANSI color escape sequences
298 WithMarkup ScopedMarkup
= markup(O
, Markup::Immediate
);
299 RISCVZC::printSpimm(Spimm
, O
);
302 void RISCVInstPrinter::printVMaskReg(const MCInst
*MI
, unsigned OpNo
,
303 const MCSubtargetInfo
&STI
,
305 const MCOperand
&MO
= MI
->getOperand(OpNo
);
307 assert(MO
.isReg() && "printVMaskReg can only print register operands");
308 if (MO
.getReg() == RISCV::NoRegister
)
311 printRegName(O
, MO
.getReg());
315 const char *RISCVInstPrinter::getRegisterName(MCRegister Reg
) {
316 return getRegisterName(Reg
, ArchRegNames
? RISCV::NoRegAltName
317 : RISCV::ABIRegAltName
);