1 //===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===//
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 file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to the RISCV assembly language.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/RISCVInstPrinter.h"
15 #include "MCTargetDesc/RISCVMCExpr.h"
16 #include "MCTargetDesc/RISCVTargetStreamer.h"
18 #include "RISCVTargetMachine.h"
19 #include "TargetInfo/RISCVTargetInfo.h"
20 #include "llvm/ADT/Statistic.h"
21 #include "llvm/CodeGen/AsmPrinter.h"
22 #include "llvm/CodeGen/MachineConstantPool.h"
23 #include "llvm/CodeGen/MachineFunctionPass.h"
24 #include "llvm/CodeGen/MachineInstr.h"
25 #include "llvm/CodeGen/MachineModuleInfo.h"
26 #include "llvm/MC/MCAsmInfo.h"
27 #include "llvm/MC/MCInst.h"
28 #include "llvm/MC/MCStreamer.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/Support/TargetRegistry.h"
31 #include "llvm/Support/raw_ostream.h"
34 #define DEBUG_TYPE "asm-printer"
36 STATISTIC(RISCVNumInstrsCompressed
,
37 "Number of RISC-V Compressed instructions emitted");
40 class RISCVAsmPrinter
: public AsmPrinter
{
41 const MCSubtargetInfo
*STI
;
44 explicit RISCVAsmPrinter(TargetMachine
&TM
,
45 std::unique_ptr
<MCStreamer
> Streamer
)
46 : AsmPrinter(TM
, std::move(Streamer
)), STI(TM
.getMCSubtargetInfo()) {}
48 StringRef
getPassName() const override
{ return "RISCV Assembly Printer"; }
50 bool runOnMachineFunction(MachineFunction
&MF
) override
;
52 void emitInstruction(const MachineInstr
*MI
) override
;
54 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
55 const char *ExtraCode
, raw_ostream
&OS
) override
;
56 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
57 const char *ExtraCode
, raw_ostream
&OS
) override
;
59 void EmitToStreamer(MCStreamer
&S
, const MCInst
&Inst
);
60 bool emitPseudoExpansionLowering(MCStreamer
&OutStreamer
,
61 const MachineInstr
*MI
);
63 // Wrapper needed for tblgenned pseudo lowering.
64 bool lowerOperand(const MachineOperand
&MO
, MCOperand
&MCOp
) const {
65 return LowerRISCVMachineOperandToMCOperand(MO
, MCOp
, *this);
68 void emitStartOfAsmFile(Module
&M
) override
;
69 void emitEndOfAsmFile(Module
&M
) override
;
72 void emitAttributes();
76 #define GEN_COMPRESS_INSTR
77 #include "RISCVGenCompressInstEmitter.inc"
78 void RISCVAsmPrinter::EmitToStreamer(MCStreamer
&S
, const MCInst
&Inst
) {
80 bool Res
= compressInst(CInst
, Inst
, *STI
, OutStreamer
->getContext());
82 ++RISCVNumInstrsCompressed
;
83 AsmPrinter::EmitToStreamer(*OutStreamer
, Res
? CInst
: Inst
);
86 // Simple pseudo-instructions have their lowering (with expansion to real
87 // instructions) auto-generated.
88 #include "RISCVGenMCPseudoLowering.inc"
90 void RISCVAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
91 // Do any auto-generated pseudo lowerings.
92 if (emitPseudoExpansionLowering(*OutStreamer
, MI
))
96 if (!lowerRISCVMachineInstrToMCInst(MI
, TmpInst
, *this))
97 EmitToStreamer(*OutStreamer
, TmpInst
);
100 bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
101 const char *ExtraCode
, raw_ostream
&OS
) {
102 // First try the generic code, which knows about modifiers like 'c' and 'n'.
103 if (!AsmPrinter::PrintAsmOperand(MI
, OpNo
, ExtraCode
, OS
))
106 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
107 if (ExtraCode
&& ExtraCode
[0]) {
108 if (ExtraCode
[1] != 0)
109 return true; // Unknown modifier.
111 switch (ExtraCode
[0]) {
113 return true; // Unknown modifier.
114 case 'z': // Print zero register if zero, regular printing otherwise.
115 if (MO
.isImm() && MO
.getImm() == 0) {
116 OS
<< RISCVInstPrinter::getRegisterName(RISCV::X0
);
120 case 'i': // Literal 'i' if operand is not a register.
127 switch (MO
.getType()) {
128 case MachineOperand::MO_Immediate
:
131 case MachineOperand::MO_Register
:
132 OS
<< RISCVInstPrinter::getRegisterName(MO
.getReg());
134 case MachineOperand::MO_GlobalAddress
:
135 PrintSymbolOperand(MO
, OS
);
137 case MachineOperand::MO_BlockAddress
: {
138 MCSymbol
*Sym
= GetBlockAddressSymbol(MO
.getBlockAddress());
149 bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
151 const char *ExtraCode
,
154 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
155 // For now, we only support register memory operands in registers and
156 // assume there is no addend
160 OS
<< "0(" << RISCVInstPrinter::getRegisterName(MO
.getReg()) << ")";
164 return AsmPrinter::PrintAsmMemoryOperand(MI
, OpNo
, ExtraCode
, OS
);
167 bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction
&MF
) {
168 // Set the current MCSubtargetInfo to a copy which has the correct
169 // feature bits for the current MachineFunction
170 MCSubtargetInfo
&NewSTI
=
171 OutStreamer
->getContext().getSubtargetCopy(*TM
.getMCSubtargetInfo());
172 NewSTI
.setFeatureBits(MF
.getSubtarget().getFeatureBits());
175 SetupMachineFunction(MF
);
180 void RISCVAsmPrinter::emitStartOfAsmFile(Module
&M
) {
181 if (TM
.getTargetTriple().isOSBinFormatELF())
185 void RISCVAsmPrinter::emitEndOfAsmFile(Module
&M
) {
186 RISCVTargetStreamer
&RTS
=
187 static_cast<RISCVTargetStreamer
&>(*OutStreamer
->getTargetStreamer());
189 if (TM
.getTargetTriple().isOSBinFormatELF())
190 RTS
.finishAttributeSection();
193 void RISCVAsmPrinter::emitAttributes() {
194 RISCVTargetStreamer
&RTS
=
195 static_cast<RISCVTargetStreamer
&>(*OutStreamer
->getTargetStreamer());
196 RTS
.emitTargetAttributes(*STI
);
199 // Force static initialization.
200 extern "C" LLVM_EXTERNAL_VISIBILITY
void LLVMInitializeRISCVAsmPrinter() {
201 RegisterAsmPrinter
<RISCVAsmPrinter
> X(getTheRISCV32Target());
202 RegisterAsmPrinter
<RISCVAsmPrinter
> Y(getTheRISCV64Target());