1//===-- BPFAsmPrinter.cpp - BPF 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 BPF assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "BPFAsmPrinter.h"
15#include "BPF.h"
16#include "BPFInstrInfo.h"
17#include "BPFMCInstLower.h"
18#include "BTFDebug.h"
19#include "MCTargetDesc/BPFInstPrinter.h"
20#include "TargetInfo/BPFTargetInfo.h"
21#include "llvm/BinaryFormat/ELF.h"
22#include "llvm/CodeGen/AsmPrinter.h"
23#include "llvm/CodeGen/MachineConstantPool.h"
24#include "llvm/CodeGen/MachineInstr.h"
25#include "llvm/CodeGen/MachineJumpTableInfo.h"
26#include "llvm/CodeGen/MachineModuleInfo.h"
27#include "llvm/CodeGen/TargetLowering.h"
28#include "llvm/IR/Module.h"
29#include "llvm/MC/MCAsmInfo.h"
30#include "llvm/MC/MCExpr.h"
31#include "llvm/MC/MCInst.h"
32#include "llvm/MC/MCStreamer.h"
33#include "llvm/MC/MCSymbol.h"
34#include "llvm/MC/MCSymbolELF.h"
35#include "llvm/MC/TargetRegistry.h"
36#include "llvm/Support/Compiler.h"
37#include "llvm/Support/raw_ostream.h"
38#include "llvm/Target/TargetLoweringObjectFile.h"
39using namespace llvm;
40
41#define DEBUG_TYPE "asm-printer"
42
43bool BPFAsmPrinter::doInitialization(Module &M) {
44 AsmPrinter::doInitialization(M);
45
46 // Only emit BTF when debuginfo available.
47 if (MAI->doesSupportDebugInformation() && !M.debug_compile_units().empty()) {
48 BTF = new BTFDebug(this);
49 Handlers.push_back(Elt: std::unique_ptr<BTFDebug>(BTF));
50 }
51
52 return false;
53}
54
55const BPFTargetMachine &BPFAsmPrinter::getBTM() const {
56 return static_cast<const BPFTargetMachine &>(TM);
57}
58
59bool BPFAsmPrinter::doFinalization(Module &M) {
60 // Remove unused globals which are previously used for jump table.
61 const BPFSubtarget *Subtarget = getBTM().getSubtargetImpl();
62 if (Subtarget->hasGotox()) {
63 std::vector<GlobalVariable *> Targets;
64 for (GlobalVariable &Global : M.globals()) {
65 if (Global.getLinkage() != GlobalValue::PrivateLinkage)
66 continue;
67 if (!Global.isConstant() || !Global.hasInitializer())
68 continue;
69
70 Constant *CV = dyn_cast<Constant>(Val: Global.getInitializer());
71 if (!CV)
72 continue;
73 ConstantArray *CA = dyn_cast<ConstantArray>(Val: CV);
74 if (!CA)
75 continue;
76
77 for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) {
78 if (!dyn_cast<BlockAddress>(Val: CA->getOperand(i_nocapture: i)))
79 continue;
80 }
81 Targets.push_back(x: &Global);
82 }
83
84 for (GlobalVariable *GV : Targets) {
85 GV->replaceAllUsesWith(V: PoisonValue::get(T: GV->getType()));
86 GV->dropAllReferences();
87 GV->eraseFromParent();
88 }
89 }
90
91 for (GlobalObject &GO : M.global_objects()) {
92 if (!GO.hasExternalWeakLinkage())
93 continue;
94
95 if (!SawTrapCall && GO.getName() == BPF_TRAP) {
96 GO.eraseFromParent();
97 break;
98 }
99 }
100
101 return AsmPrinter::doFinalization(M);
102}
103
104void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
105 raw_ostream &O) {
106 const MachineOperand &MO = MI->getOperand(i: OpNum);
107
108 switch (MO.getType()) {
109 case MachineOperand::MO_Register:
110 O << BPFInstPrinter::getRegisterName(Reg: MO.getReg());
111 break;
112
113 case MachineOperand::MO_Immediate:
114 O << MO.getImm();
115 break;
116
117 case MachineOperand::MO_MachineBasicBlock:
118 O << *MO.getMBB()->getSymbol();
119 break;
120
121 case MachineOperand::MO_GlobalAddress:
122 O << *getSymbol(GV: MO.getGlobal());
123 break;
124
125 case MachineOperand::MO_BlockAddress: {
126 MCSymbol *BA = GetBlockAddressSymbol(BA: MO.getBlockAddress());
127 O << BA->getName();
128 break;
129 }
130
131 case MachineOperand::MO_ExternalSymbol:
132 O << *GetExternalSymbolSymbol(Sym: MO.getSymbolName());
133 break;
134
135 case MachineOperand::MO_JumpTableIndex:
136 case MachineOperand::MO_ConstantPoolIndex:
137 default:
138 llvm_unreachable("<unknown operand type>");
139 }
140}
141
142bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
143 const char *ExtraCode, raw_ostream &O) {
144 if (ExtraCode && ExtraCode[0])
145 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O);
146
147 printOperand(MI, OpNum: OpNo, O);
148 return false;
149}
150
151bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
152 unsigned OpNum, const char *ExtraCode,
153 raw_ostream &O) {
154 assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
155 const MachineOperand &BaseMO = MI->getOperand(i: OpNum);
156 const MachineOperand &OffsetMO = MI->getOperand(i: OpNum + 1);
157 assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand.");
158 assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand.");
159 int Offset = OffsetMO.getImm();
160
161 if (ExtraCode)
162 return true; // Unknown modifier.
163
164 if (Offset < 0)
165 O << "(" << BPFInstPrinter::getRegisterName(Reg: BaseMO.getReg()) << " - " << -Offset << ")";
166 else
167 O << "(" << BPFInstPrinter::getRegisterName(Reg: BaseMO.getReg()) << " + " << Offset << ")";
168
169 return false;
170}
171
172void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) {
173 if (MI->isCall()) {
174 for (const MachineOperand &Op : MI->operands()) {
175 if (Op.isGlobal()) {
176 if (const GlobalValue *GV = Op.getGlobal())
177 if (GV->getName() == BPF_TRAP)
178 SawTrapCall = true;
179 }
180 }
181 }
182
183 BPF_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(),
184 Features: getSubtargetInfo().getFeatureBits());
185
186 MCInst TmpInst;
187
188 if (!BTF || !BTF->InstLower(MI, OutMI&: TmpInst)) {
189 BPFMCInstLower MCInstLowering(OutContext, *this);
190 MCInstLowering.Lower(MI, OutMI&: TmpInst);
191 }
192 EmitToStreamer(S&: *OutStreamer, Inst: TmpInst);
193}
194
195MCSymbol *BPFAsmPrinter::getJTPublicSymbol(unsigned JTI) {
196 SmallString<60> Name;
197 raw_svector_ostream(Name)
198 << "BPF.JT." << MF->getFunctionNumber() << '.' << JTI;
199 MCSymbol *S = OutContext.getOrCreateSymbol(Name);
200 if (auto *ES = static_cast<MCSymbolELF *>(S)) {
201 ES->setBinding(ELF::STB_GLOBAL);
202 ES->setType(ELF::STT_OBJECT);
203 }
204 return S;
205}
206
207void BPFAsmPrinter::emitJumpTableInfo() {
208 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
209 if (!MJTI)
210 return;
211
212 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
213 if (JT.empty())
214 return;
215
216 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
217 const Function &F = MF->getFunction();
218
219 MCSection *Sec = OutStreamer->getCurrentSectionOnly();
220 MCSymbol *SecStart = Sec->getBeginSymbol();
221
222 MCSection *JTS = TLOF.getSectionForJumpTable(F, TM);
223 assert(MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress);
224 unsigned EntrySize = MJTI->getEntrySize(TD: getDataLayout());
225 OutStreamer->switchSection(Section: JTS);
226 for (unsigned JTI = 0; JTI < JT.size(); JTI++) {
227 ArrayRef<MachineBasicBlock *> JTBBs = JT[JTI].MBBs;
228 if (JTBBs.empty())
229 continue;
230
231 MCSymbol *JTStart = getJTPublicSymbol(JTI);
232 OutStreamer->emitLabel(Symbol: JTStart);
233 for (const MachineBasicBlock *MBB : JTBBs) {
234 const MCExpr *Diff = MCBinaryExpr::createSub(
235 LHS: MCSymbolRefExpr::create(Symbol: MBB->getSymbol(), Ctx&: OutContext),
236 RHS: MCSymbolRefExpr::create(Symbol: SecStart, Ctx&: OutContext), Ctx&: OutContext);
237 OutStreamer->emitValue(Value: Diff, Size: EntrySize);
238 }
239 const MCExpr *JTSize =
240 MCConstantExpr::create(Value: JTBBs.size() * EntrySize, Ctx&: OutContext);
241 OutStreamer->emitELFSize(Symbol: JTStart, Value: JTSize);
242 }
243}
244
245char BPFAsmPrinter::ID = 0;
246
247INITIALIZE_PASS(BPFAsmPrinter, "bpf-asm-printer", "BPF Assembly Printer", false,
248 false)
249
250// Force static initialization.
251extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
252LLVMInitializeBPFAsmPrinter() {
253 RegisterAsmPrinter<BPFAsmPrinter> X(getTheBPFleTarget());
254 RegisterAsmPrinter<BPFAsmPrinter> Y(getTheBPFbeTarget());
255 RegisterAsmPrinter<BPFAsmPrinter> Z(getTheBPFTarget());
256}
257