1 //===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===//
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 file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to the RISCV assembly language.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "MCTargetDesc/RISCVInstPrinter.h"
15 #include "MCTargetDesc/RISCVMCExpr.h"
16 #include "MCTargetDesc/RISCVTargetStreamer.h"
17 #include "RISCV.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"
32 using namespace llvm;
33
34 #define DEBUG_TYPE "asm-printer"
35
36 STATISTIC(RISCVNumInstrsCompressed,
37 "Number of RISC-V Compressed instructions emitted");
38
39 namespace {
40 class RISCVAsmPrinter : public AsmPrinter {
41 const MCSubtargetInfo *STI;
42
43 public:
RISCVAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)44 explicit RISCVAsmPrinter(TargetMachine &TM,
45 std::unique_ptr<MCStreamer> Streamer)
46 : AsmPrinter(TM, std::move(Streamer)), STI(TM.getMCSubtargetInfo()) {}
47
getPassName() const48 StringRef getPassName() const override { return "RISCV Assembly Printer"; }
49
50 bool runOnMachineFunction(MachineFunction &MF) override;
51
52 void emitInstruction(const MachineInstr *MI) override;
53
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;
58
59 void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
60 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
61 const MachineInstr *MI);
62
63 // Wrapper needed for tblgenned pseudo lowering.
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const64 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
65 return LowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
66 }
67
68 void emitStartOfAsmFile(Module &M) override;
69 void emitEndOfAsmFile(Module &M) override;
70
71 private:
72 void emitAttributes();
73 };
74 }
75
76 #define GEN_COMPRESS_INSTR
77 #include "RISCVGenCompressInstEmitter.inc"
EmitToStreamer(MCStreamer & S,const MCInst & Inst)78 void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
79 MCInst CInst;
80 bool Res = compressInst(CInst, Inst, *STI, OutStreamer->getContext());
81 if (Res)
82 ++RISCVNumInstrsCompressed;
83 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
84 }
85
86 // Simple pseudo-instructions have their lowering (with expansion to real
87 // instructions) auto-generated.
88 #include "RISCVGenMCPseudoLowering.inc"
89
emitInstruction(const MachineInstr * MI)90 void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
91 // Do any auto-generated pseudo lowerings.
92 if (emitPseudoExpansionLowering(*OutStreamer, MI))
93 return;
94
95 MCInst TmpInst;
96 LowerRISCVMachineInstrToMCInst(MI, TmpInst, *this);
97 EmitToStreamer(*OutStreamer, TmpInst);
98 }
99
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)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))
104 return false;
105
106 const MachineOperand &MO = MI->getOperand(OpNo);
107 if (ExtraCode && ExtraCode[0]) {
108 if (ExtraCode[1] != 0)
109 return true; // Unknown modifier.
110
111 switch (ExtraCode[0]) {
112 default:
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);
117 return false;
118 }
119 break;
120 case 'i': // Literal 'i' if operand is not a register.
121 if (!MO.isReg())
122 OS << 'i';
123 return false;
124 }
125 }
126
127 switch (MO.getType()) {
128 case MachineOperand::MO_Immediate:
129 OS << MO.getImm();
130 return false;
131 case MachineOperand::MO_Register:
132 OS << RISCVInstPrinter::getRegisterName(MO.getReg());
133 return false;
134 case MachineOperand::MO_GlobalAddress:
135 PrintSymbolOperand(MO, OS);
136 return false;
137 case MachineOperand::MO_BlockAddress: {
138 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
139 Sym->print(OS, MAI);
140 return false;
141 }
142 default:
143 break;
144 }
145
146 return true;
147 }
148
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)149 bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
150 unsigned OpNo,
151 const char *ExtraCode,
152 raw_ostream &OS) {
153 if (!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
157 if (!MO.isReg())
158 return true;
159
160 OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")";
161 return false;
162 }
163
164 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
165 }
166
runOnMachineFunction(MachineFunction & MF)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());
173 STI = &NewSTI;
174
175 SetupMachineFunction(MF);
176 emitFunctionBody();
177 return false;
178 }
179
emitStartOfAsmFile(Module & M)180 void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
181 if (TM.getTargetTriple().isOSBinFormatELF())
182 emitAttributes();
183 }
184
emitEndOfAsmFile(Module & M)185 void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
186 RISCVTargetStreamer &RTS =
187 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
188
189 if (TM.getTargetTriple().isOSBinFormatELF())
190 RTS.finishAttributeSection();
191 }
192
emitAttributes()193 void RISCVAsmPrinter::emitAttributes() {
194 RISCVTargetStreamer &RTS =
195 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
196
197 const Triple &TT = TM.getTargetTriple();
198 StringRef CPU = TM.getTargetCPU();
199 StringRef FS = TM.getTargetFeatureString();
200 const RISCVTargetMachine &RTM = static_cast<const RISCVTargetMachine &>(TM);
201 /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only
202 care about arch related features, so we can set TuneCPU as CPU. */
203 const RISCVSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, /*ABIName=*/"", RTM);
204
205 RTS.emitTargetAttributes(STI);
206 }
207
208 // Force static initialization.
LLVMInitializeRISCVAsmPrinter()209 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
210 RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
211 RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
212 }
213