xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- RISCVInstPrinter.cpp - Convert RISC-V MCInst to asm syntax --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
906c3fb27SDimitry Andric // This class prints an RISC-V MCInst to a .s file.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "RISCVInstPrinter.h"
14e8d8bef9SDimitry Andric #include "RISCVBaseInfo.h"
15e8d8bef9SDimitry Andric #include "RISCVMCExpr.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
195f757f3fSDimitry Andric #include "llvm/MC/MCInstPrinter.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
230b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
240b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
250b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric // Include the auto-generated portion of the assembly writer.
310b57cec5SDimitry Andric #define PRINT_ALIAS_INSTR
320b57cec5SDimitry Andric #include "RISCVGenAsmWriter.inc"
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric static cl::opt<bool>
350b57cec5SDimitry Andric     NoAliases("riscv-no-aliases",
360b57cec5SDimitry Andric               cl::desc("Disable the emission of assembler pseudo instructions"),
370b57cec5SDimitry Andric               cl::init(false), cl::Hidden);
380b57cec5SDimitry Andric 
39fe6060f1SDimitry Andric // Print architectural register names rather than the ABI names (such as x2
40fe6060f1SDimitry Andric // instead of sp).
41fe6060f1SDimitry Andric // TODO: Make RISCVInstPrinter::getRegisterName non-static so that this can a
42fe6060f1SDimitry Andric // member.
43fe6060f1SDimitry Andric static bool ArchRegNames;
448bcb0991SDimitry Andric 
458bcb0991SDimitry Andric // The command-line flags above are used by llvm-mc and llc. They can be used by
468bcb0991SDimitry Andric // `llvm-objdump`, but we override their values here to handle options passed to
478bcb0991SDimitry Andric // `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to
488bcb0991SDimitry Andric // be an easier way to allow these options in all these tools, without doing it
498bcb0991SDimitry Andric // this way.
508bcb0991SDimitry Andric bool RISCVInstPrinter::applyTargetSpecificCLOption(StringRef Opt) {
518bcb0991SDimitry Andric   if (Opt == "no-aliases") {
52fe6060f1SDimitry Andric     PrintAliases = false;
538bcb0991SDimitry Andric     return true;
548bcb0991SDimitry Andric   }
558bcb0991SDimitry Andric   if (Opt == "numeric") {
568bcb0991SDimitry Andric     ArchRegNames = true;
578bcb0991SDimitry Andric     return true;
588bcb0991SDimitry Andric   }
598bcb0991SDimitry Andric 
608bcb0991SDimitry Andric   return false;
618bcb0991SDimitry Andric }
628bcb0991SDimitry Andric 
63480093f4SDimitry Andric void RISCVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
64480093f4SDimitry Andric                                  StringRef Annot, const MCSubtargetInfo &STI,
65480093f4SDimitry Andric                                  raw_ostream &O) {
660b57cec5SDimitry Andric   bool Res = false;
670b57cec5SDimitry Andric   const MCInst *NewMI = MI;
680b57cec5SDimitry Andric   MCInst UncompressedMI;
69fe6060f1SDimitry Andric   if (PrintAliases && !NoAliases)
70bdd1243dSDimitry Andric     Res = RISCVRVC::uncompress(UncompressedMI, *MI, STI);
710b57cec5SDimitry Andric   if (Res)
720b57cec5SDimitry Andric     NewMI = const_cast<MCInst *>(&UncompressedMI);
73fe6060f1SDimitry Andric   if (!PrintAliases || NoAliases || !printAliasInstr(NewMI, Address, STI, O))
74480093f4SDimitry Andric     printInstruction(NewMI, Address, STI, O);
750b57cec5SDimitry Andric   printAnnotation(O, Annot);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
78bdd1243dSDimitry Andric void RISCVInstPrinter::printRegName(raw_ostream &O, MCRegister Reg) const {
795f757f3fSDimitry Andric   markup(O, Markup::Register) << getRegisterName(Reg);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
830b57cec5SDimitry Andric                                     const MCSubtargetInfo &STI, raw_ostream &O,
840b57cec5SDimitry Andric                                     const char *Modifier) {
8504eeddc0SDimitry Andric   assert((Modifier == nullptr || Modifier[0] == 0) && "No modifiers supported");
860b57cec5SDimitry Andric   const MCOperand &MO = MI->getOperand(OpNo);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   if (MO.isReg()) {
890b57cec5SDimitry Andric     printRegName(O, MO.getReg());
900b57cec5SDimitry Andric     return;
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   if (MO.isImm()) {
945f757f3fSDimitry Andric     markup(O, Markup::Immediate) << formatImm(MO.getImm());
950b57cec5SDimitry Andric     return;
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   assert(MO.isExpr() && "Unknown operand kind in printOperand");
990b57cec5SDimitry Andric   MO.getExpr()->print(O, &MAI);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
102e8d8bef9SDimitry Andric void RISCVInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address,
103e8d8bef9SDimitry Andric                                           unsigned OpNo,
104e8d8bef9SDimitry Andric                                           const MCSubtargetInfo &STI,
105e8d8bef9SDimitry Andric                                           raw_ostream &O) {
106e8d8bef9SDimitry Andric   const MCOperand &MO = MI->getOperand(OpNo);
107e8d8bef9SDimitry Andric   if (!MO.isImm())
108e8d8bef9SDimitry Andric     return printOperand(MI, OpNo, STI, O);
109e8d8bef9SDimitry Andric 
110e8d8bef9SDimitry Andric   if (PrintBranchImmAsAddress) {
111e8d8bef9SDimitry Andric     uint64_t Target = Address + MO.getImm();
112e8d8bef9SDimitry Andric     if (!STI.hasFeature(RISCV::Feature64Bit))
113e8d8bef9SDimitry Andric       Target &= 0xffffffff;
1145f757f3fSDimitry Andric     markup(O, Markup::Target) << formatHex(Target);
115e8d8bef9SDimitry Andric   } else {
1165f757f3fSDimitry Andric     markup(O, Markup::Target) << formatImm(MO.getImm());
117e8d8bef9SDimitry Andric   }
118e8d8bef9SDimitry Andric }
119e8d8bef9SDimitry Andric 
1200b57cec5SDimitry Andric void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo,
1210b57cec5SDimitry Andric                                               const MCSubtargetInfo &STI,
1220b57cec5SDimitry Andric                                               raw_ostream &O) {
1230b57cec5SDimitry Andric   unsigned Imm = MI->getOperand(OpNo).getImm();
124*0fca6ea1SDimitry Andric   auto Range = RISCVSysReg::lookupSysRegByEncoding(Imm);
125*0fca6ea1SDimitry Andric   for (auto &Reg : Range) {
126*0fca6ea1SDimitry Andric     if (Reg.haveRequiredFeatures(STI.getFeatureBits())) {
127*0fca6ea1SDimitry Andric       markup(O, Markup::Register) << Reg.Name;
128*0fca6ea1SDimitry Andric       return;
129*0fca6ea1SDimitry Andric     }
130*0fca6ea1SDimitry Andric   }
1315f757f3fSDimitry Andric   markup(O, Markup::Register) << formatImm(Imm);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric void RISCVInstPrinter::printFenceArg(const MCInst *MI, unsigned OpNo,
1350b57cec5SDimitry Andric                                      const MCSubtargetInfo &STI,
1360b57cec5SDimitry Andric                                      raw_ostream &O) {
1370b57cec5SDimitry Andric   unsigned FenceArg = MI->getOperand(OpNo).getImm();
1380b57cec5SDimitry Andric   assert (((FenceArg >> 4) == 0) && "Invalid immediate in printFenceArg");
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if ((FenceArg & RISCVFenceField::I) != 0)
1410b57cec5SDimitry Andric     O << 'i';
1420b57cec5SDimitry Andric   if ((FenceArg & RISCVFenceField::O) != 0)
1430b57cec5SDimitry Andric     O << 'o';
1440b57cec5SDimitry Andric   if ((FenceArg & RISCVFenceField::R) != 0)
1450b57cec5SDimitry Andric     O << 'r';
1460b57cec5SDimitry Andric   if ((FenceArg & RISCVFenceField::W) != 0)
1470b57cec5SDimitry Andric     O << 'w';
1480b57cec5SDimitry Andric   if (FenceArg == 0)
14981ad6265SDimitry Andric     O << "0";
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo,
1530b57cec5SDimitry Andric                                    const MCSubtargetInfo &STI, raw_ostream &O) {
1540b57cec5SDimitry Andric   auto FRMArg =
1550b57cec5SDimitry Andric       static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
15606c3fb27SDimitry Andric   if (PrintAliases && !NoAliases && FRMArg == RISCVFPRndMode::RoundingMode::DYN)
15706c3fb27SDimitry Andric     return;
15806c3fb27SDimitry Andric   O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
15906c3fb27SDimitry Andric }
16006c3fb27SDimitry Andric 
1615f757f3fSDimitry Andric void RISCVInstPrinter::printFRMArgLegacy(const MCInst *MI, unsigned OpNo,
1625f757f3fSDimitry Andric                                          const MCSubtargetInfo &STI,
1635f757f3fSDimitry Andric                                          raw_ostream &O) {
1645f757f3fSDimitry Andric   auto FRMArg =
1655f757f3fSDimitry Andric       static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
1665f757f3fSDimitry Andric   // Never print rounding mode if it's the default 'rne'. This ensures the
1675f757f3fSDimitry Andric   // output can still be parsed by older tools that erroneously failed to
1685f757f3fSDimitry Andric   // accept a rounding mode.
1695f757f3fSDimitry Andric   if (FRMArg == RISCVFPRndMode::RoundingMode::RNE)
1705f757f3fSDimitry Andric     return;
1715f757f3fSDimitry Andric   O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
1725f757f3fSDimitry Andric }
1735f757f3fSDimitry Andric 
17406c3fb27SDimitry Andric void RISCVInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNo,
17506c3fb27SDimitry Andric                                          const MCSubtargetInfo &STI,
17606c3fb27SDimitry Andric                                          raw_ostream &O) {
17706c3fb27SDimitry Andric   unsigned Imm = MI->getOperand(OpNo).getImm();
17806c3fb27SDimitry Andric   if (Imm == 1) {
1795f757f3fSDimitry Andric     markup(O, Markup::Immediate) << "min";
18006c3fb27SDimitry Andric   } else if (Imm == 30) {
1815f757f3fSDimitry Andric     markup(O, Markup::Immediate) << "inf";
18206c3fb27SDimitry Andric   } else if (Imm == 31) {
1835f757f3fSDimitry Andric     markup(O, Markup::Immediate) << "nan";
18406c3fb27SDimitry Andric   } else {
18506c3fb27SDimitry Andric     float FPVal = RISCVLoadFPImm::getFPImm(Imm);
18606c3fb27SDimitry Andric     // If the value is an integer, print a .0 fraction. Otherwise, use %g to
18706c3fb27SDimitry Andric     // which will not print trailing zeros and will use scientific notation
18806c3fb27SDimitry Andric     // if it is shorter than printing as a decimal. The smallest value requires
18906c3fb27SDimitry Andric     // 12 digits of precision including the decimal.
19006c3fb27SDimitry Andric     if (FPVal == (int)(FPVal))
1915f757f3fSDimitry Andric       markup(O, Markup::Immediate) << format("%.1f", FPVal);
19206c3fb27SDimitry Andric     else
1935f757f3fSDimitry Andric       markup(O, Markup::Immediate) << format("%.12g", FPVal);
19406c3fb27SDimitry Andric   }
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric 
19781ad6265SDimitry Andric void RISCVInstPrinter::printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo,
1980b57cec5SDimitry Andric                                             const MCSubtargetInfo &STI,
1990b57cec5SDimitry Andric                                             raw_ostream &O) {
2000b57cec5SDimitry Andric   const MCOperand &MO = MI->getOperand(OpNo);
2010b57cec5SDimitry Andric 
20281ad6265SDimitry Andric   assert(MO.isReg() && "printZeroOffsetMemOp can only print register operands");
2030b57cec5SDimitry Andric   O << "(";
2040b57cec5SDimitry Andric   printRegName(O, MO.getReg());
2050b57cec5SDimitry Andric   O << ")";
2060b57cec5SDimitry Andric }
2078bcb0991SDimitry Andric 
2085ffd83dbSDimitry Andric void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
2095ffd83dbSDimitry Andric                                    const MCSubtargetInfo &STI, raw_ostream &O) {
2105ffd83dbSDimitry Andric   unsigned Imm = MI->getOperand(OpNo).getImm();
2114824e7fdSDimitry Andric   // Print the raw immediate for reserved values: vlmul[2:0]=4, vsew[2:0]=0b1xx,
2120eae32dcSDimitry Andric   // or non-zero in bits 8 and above.
2134824e7fdSDimitry Andric   if (RISCVVType::getVLMUL(Imm) == RISCVII::VLMUL::LMUL_RESERVED ||
2140eae32dcSDimitry Andric       RISCVVType::getSEW(Imm) > 64 || (Imm >> 8) != 0) {
2155f757f3fSDimitry Andric     O << formatImm(Imm);
2164824e7fdSDimitry Andric     return;
2174824e7fdSDimitry Andric   }
2184824e7fdSDimitry Andric   // Print the text form.
219e8d8bef9SDimitry Andric   RISCVVType::printVType(Imm, O);
2205ffd83dbSDimitry Andric }
2215ffd83dbSDimitry Andric 
222*0fca6ea1SDimitry Andric // Print a Zcmp RList. If we are printing architectural register names rather
223*0fca6ea1SDimitry Andric // than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all
224*0fca6ea1SDimitry Andric // registers. Otherwise, we print "{ra, s0-s11}".
22506c3fb27SDimitry Andric void RISCVInstPrinter::printRlist(const MCInst *MI, unsigned OpNo,
22606c3fb27SDimitry Andric                                   const MCSubtargetInfo &STI, raw_ostream &O) {
22706c3fb27SDimitry Andric   unsigned Imm = MI->getOperand(OpNo).getImm();
22806c3fb27SDimitry Andric   O << "{";
229*0fca6ea1SDimitry Andric   printRegName(O, RISCV::X1);
230*0fca6ea1SDimitry Andric 
231*0fca6ea1SDimitry Andric   if (Imm >= RISCVZC::RLISTENCODE::RA_S0) {
2325f757f3fSDimitry Andric     O << ", ";
233*0fca6ea1SDimitry Andric     printRegName(O, RISCV::X8);
2345f757f3fSDimitry Andric   }
235*0fca6ea1SDimitry Andric 
236*0fca6ea1SDimitry Andric   if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S1) {
2375f757f3fSDimitry Andric     O << '-';
238*0fca6ea1SDimitry Andric     if (Imm == RISCVZC::RLISTENCODE::RA_S0_S1 || ArchRegNames)
239*0fca6ea1SDimitry Andric       printRegName(O, RISCV::X9);
240*0fca6ea1SDimitry Andric   }
241*0fca6ea1SDimitry Andric 
242*0fca6ea1SDimitry Andric   if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S2) {
243*0fca6ea1SDimitry Andric     if (ArchRegNames)
2445f757f3fSDimitry Andric       O << ", ";
245*0fca6ea1SDimitry Andric     if (Imm == RISCVZC::RLISTENCODE::RA_S0_S2 || ArchRegNames)
246*0fca6ea1SDimitry Andric       printRegName(O, RISCV::X18);
247*0fca6ea1SDimitry Andric   }
248*0fca6ea1SDimitry Andric 
249*0fca6ea1SDimitry Andric   if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S3) {
250*0fca6ea1SDimitry Andric     if (ArchRegNames)
2515f757f3fSDimitry Andric       O << '-';
252*0fca6ea1SDimitry Andric     unsigned Offset = (Imm - RISCVZC::RLISTENCODE::RA_S0_S3);
253*0fca6ea1SDimitry Andric     // Encodings for S3-S9 are contiguous. There is no encoding for S10, so we
254*0fca6ea1SDimitry Andric     // must skip to S11(X27).
255*0fca6ea1SDimitry Andric     if (Imm == RISCVZC::RLISTENCODE::RA_S0_S11)
256*0fca6ea1SDimitry Andric       ++Offset;
257*0fca6ea1SDimitry Andric     printRegName(O, RISCV::X19 + Offset);
2585f757f3fSDimitry Andric   }
259*0fca6ea1SDimitry Andric 
26006c3fb27SDimitry Andric   O << "}";
26106c3fb27SDimitry Andric }
26206c3fb27SDimitry Andric 
2635f757f3fSDimitry Andric void RISCVInstPrinter::printRegReg(const MCInst *MI, unsigned OpNo,
2645f757f3fSDimitry Andric                                    const MCSubtargetInfo &STI, raw_ostream &O) {
2655f757f3fSDimitry Andric   const MCOperand &MO = MI->getOperand(OpNo);
2665f757f3fSDimitry Andric 
2675f757f3fSDimitry Andric   assert(MO.isReg() && "printRegReg can only print register operands");
2685f757f3fSDimitry Andric   if (MO.getReg() == RISCV::NoRegister)
2695f757f3fSDimitry Andric     return;
2705f757f3fSDimitry Andric   printRegName(O, MO.getReg());
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric   O << "(";
2735f757f3fSDimitry Andric   const MCOperand &MO1 = MI->getOperand(OpNo + 1);
2745f757f3fSDimitry Andric   assert(MO1.isReg() && "printRegReg can only print register operands");
2755f757f3fSDimitry Andric   printRegName(O, MO1.getReg());
2765f757f3fSDimitry Andric   O << ")";
2775f757f3fSDimitry Andric }
2785f757f3fSDimitry Andric 
279*0fca6ea1SDimitry Andric void RISCVInstPrinter::printStackAdj(const MCInst *MI, unsigned OpNo,
280*0fca6ea1SDimitry Andric                                      const MCSubtargetInfo &STI, raw_ostream &O,
281*0fca6ea1SDimitry Andric                                      bool Negate) {
28206c3fb27SDimitry Andric   int64_t Imm = MI->getOperand(OpNo).getImm();
28306c3fb27SDimitry Andric   bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
284*0fca6ea1SDimitry Andric   int64_t StackAdj = 0;
28506c3fb27SDimitry Andric   auto RlistVal = MI->getOperand(0).getImm();
28606c3fb27SDimitry Andric   assert(RlistVal != 16 && "Incorrect rlist.");
287*0fca6ea1SDimitry Andric   auto Base = RISCVZC::getStackAdjBase(RlistVal, IsRV64);
288*0fca6ea1SDimitry Andric   StackAdj = Imm + Base;
289*0fca6ea1SDimitry Andric   assert((StackAdj >= Base && StackAdj <= Base + 48) &&
290*0fca6ea1SDimitry Andric          "Incorrect stack adjust");
291*0fca6ea1SDimitry Andric   if (Negate)
292*0fca6ea1SDimitry Andric     StackAdj = -StackAdj;
29306c3fb27SDimitry Andric 
2945f757f3fSDimitry Andric   // RAII guard for ANSI color escape sequences
2955f757f3fSDimitry Andric   WithMarkup ScopedMarkup = markup(O, Markup::Immediate);
296*0fca6ea1SDimitry Andric   O << StackAdj;
29706c3fb27SDimitry Andric }
29806c3fb27SDimitry Andric 
2995ffd83dbSDimitry Andric void RISCVInstPrinter::printVMaskReg(const MCInst *MI, unsigned OpNo,
3005ffd83dbSDimitry Andric                                      const MCSubtargetInfo &STI,
3015ffd83dbSDimitry Andric                                      raw_ostream &O) {
3025ffd83dbSDimitry Andric   const MCOperand &MO = MI->getOperand(OpNo);
3035ffd83dbSDimitry Andric 
3045ffd83dbSDimitry Andric   assert(MO.isReg() && "printVMaskReg can only print register operands");
3055ffd83dbSDimitry Andric   if (MO.getReg() == RISCV::NoRegister)
3065ffd83dbSDimitry Andric     return;
3075ffd83dbSDimitry Andric   O << ", ";
3085ffd83dbSDimitry Andric   printRegName(O, MO.getReg());
3095ffd83dbSDimitry Andric   O << ".t";
3105ffd83dbSDimitry Andric }
3115ffd83dbSDimitry Andric 
312bdd1243dSDimitry Andric const char *RISCVInstPrinter::getRegisterName(MCRegister Reg) {
313bdd1243dSDimitry Andric   return getRegisterName(Reg, ArchRegNames ? RISCV::NoRegAltName
3148bcb0991SDimitry Andric                                            : RISCV::ABIRegAltName);
3158bcb0991SDimitry Andric }
316