LLVM 23.0.0git
BPFAsmPrinter.cpp
Go to the documentation of this file.
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"
29#include "llvm/IR/Module.h"
30#include "llvm/MC/MCAsmInfo.h"
31#include "llvm/MC/MCExpr.h"
32#include "llvm/MC/MCInst.h"
34#include "llvm/MC/MCStreamer.h"
35#include "llvm/MC/MCSymbol.h"
36#include "llvm/MC/MCSymbolELF.h"
41using namespace llvm;
42
43#define DEBUG_TYPE "asm-printer"
44
47
48 // Only emit BTF when debuginfo available.
49 if (MAI->doesSupportDebugInformation() && !M.debug_compile_units().empty()) {
50 BTF = new BTFDebug(this);
51 Handlers.push_back(std::unique_ptr<BTFDebug>(BTF));
52 }
53
54 return false;
55}
56
57const BPFTargetMachine &BPFAsmPrinter::getBTM() const {
58 return static_cast<const BPFTargetMachine &>(TM);
59}
60
62 // Remove unused globals which are previously used for jump table.
63 const BPFSubtarget *Subtarget = getBTM().getSubtargetImpl();
64 if (Subtarget->hasGotox()) {
65 std::vector<GlobalVariable *> Targets;
66 for (GlobalVariable &Global : M.globals()) {
67 if (Global.getLinkage() != GlobalValue::PrivateLinkage)
68 continue;
69 if (!Global.isConstant() || !Global.hasInitializer())
70 continue;
71
72 Constant *CV = dyn_cast<Constant>(Global.getInitializer());
73 if (!CV)
74 continue;
76 if (!CA)
77 continue;
78
79 for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) {
81 continue;
82 }
83 Targets.push_back(&Global);
84 }
85
86 for (GlobalVariable *GV : Targets) {
87 GV->replaceAllUsesWith(PoisonValue::get(GV->getType()));
88 GV->dropAllReferences();
89 GV->eraseFromParent();
90 }
91 }
92
93 for (GlobalObject &GO : M.global_objects()) {
94 if (!GO.hasExternalWeakLinkage())
95 continue;
96
97 if (!SawTrapCall && GO.getName() == BPF_TRAP) {
98 GO.eraseFromParent();
99 break;
100 }
101 }
102
104}
105
107 raw_ostream &O) {
108 const MachineOperand &MO = MI->getOperand(OpNum);
109
110 switch (MO.getType()) {
113 break;
114
116 O << MO.getImm();
117 break;
118
120 O << *MO.getMBB()->getSymbol();
121 break;
122
124 O << *getSymbol(MO.getGlobal());
125 break;
126
129 O << BA->getName();
130 break;
131 }
132
135 break;
136
139 default:
140 llvm_unreachable("<unknown operand type>");
141 }
142}
143
145 const char *ExtraCode, raw_ostream &O) {
146 if (ExtraCode && ExtraCode[0])
147 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
148
149 printOperand(MI, OpNo, O);
150 return false;
151}
152
154 unsigned OpNum, const char *ExtraCode,
155 raw_ostream &O) {
156 assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
157 const MachineOperand &BaseMO = MI->getOperand(OpNum);
158 const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
159 assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand.");
160 assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand.");
161 int Offset = OffsetMO.getImm();
162
163 if (ExtraCode)
164 return true; // Unknown modifier.
165
166 if (Offset < 0)
167 O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " - " << -Offset << ")";
168 else
169 O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " + " << Offset << ")";
170
171 return false;
172}
173
175 if (MI->isCall()) {
176 for (const MachineOperand &Op : MI->operands()) {
177 if (Op.isGlobal()) {
178 if (const GlobalValue *GV = Op.getGlobal())
179 if (GV->getName() == BPF_TRAP)
180 SawTrapCall = true;
181 }
182 }
183 }
184
185 BPF_MC::verifyInstructionPredicates(MI->getOpcode(),
186 getSubtargetInfo().getFeatureBits());
187
188 MCInst TmpInst;
189
190 if (!BTF || !BTF->InstLower(MI, TmpInst)) {
191 BPFMCInstLower MCInstLowering(OutContext, *this);
192 MCInstLowering.Lower(MI, TmpInst);
193 }
194 EmitToStreamer(*OutStreamer, TmpInst);
195}
196
198 // Emit .bpf_cleanup section with a flat table of
199 // (call_site, landing_pad) pairs.
200 const std::vector<LandingPadInfo> &LandingPads = MF->getLandingPads();
201 if (LandingPads.empty())
202 return;
203
204 MCContext &Ctx = OutContext;
205 auto *CleanupSec =
206 Ctx.getELFSection(".bpf_cleanup", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
207 OutStreamer->switchSection(CleanupSec);
208
209 const auto &TypeInfos = MF->getTypeInfos();
210 const Function &F = MF->getFunction();
211 LLVMContext &LLVMCtx = F.getContext();
212
213 // Each landing pad has BeginLabels/EndLabels marking the invoke
214 // call sites that unwind to it.
215 for (const LandingPadInfo &LP : LandingPads) {
216 // BPF treats all landing pads as catch-all: the kernel redirects to
217 // the landing pad regardless of exception type. Reject type-specific
218 // catches and filters which would silently misbehave.
219 for (int TId : LP.TypeIds) {
220 if (TId > 0 && TypeInfos[TId - 1] != nullptr) {
222 F, "BPF does not support type-specific exception catches yet"));
223 return;
224 }
225 if (TId < 0) {
227 F, "BPF does not support exception filters yet"));
228 return;
229 }
230 }
231
232 MCSymbol *LPLabel = LP.LandingPadLabel;
233 if (!LPLabel)
234 continue;
235 for (unsigned i = 0, e = LP.BeginLabels.size(); i != e; ++i) {
236 MCSymbol *Begin = LP.BeginLabels[i];
237 MCSymbol *End = LP.EndLabels[i];
238
239 // Each entry is 3 x 4 bytes: begin, end, landing_pad.
240 // The invoke region [begin, end) may include argument setup
241 // before the call. The runtime checks begin <= PC < end.
242 OutStreamer->emitSymbolValue(Begin, 4);
243 OutStreamer->emitSymbolValue(End, 4);
244 OutStreamer->emitSymbolValue(LPLabel, 4);
245 }
246 }
247
248 // Switch back to the function's section.
249 OutStreamer->switchSection(MF->getSection());
250}
251
253 SmallString<60> Name;
255 << "BPF.JT." << MF->getFunctionNumber() << '.' << JTI;
256 MCSymbol *S = OutContext.getOrCreateSymbol(Name);
257 if (auto *ES = static_cast<MCSymbolELF *>(S)) {
258 ES->setBinding(ELF::STB_GLOBAL);
259 ES->setType(ELF::STT_OBJECT);
260 }
261 return S;
262}
263
265 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
266 if (!MJTI)
267 return;
268
269 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
270 if (JT.empty())
271 return;
272
274 const Function &F = MF->getFunction();
275
276 MCSection *Sec = OutStreamer->getCurrentSectionOnly();
277 MCSymbol *SecStart = Sec->getBeginSymbol();
278
279 MCSection *JTS = TLOF.getSectionForJumpTable(F, TM);
281 unsigned EntrySize = MJTI->getEntrySize(getDataLayout());
282 OutStreamer->switchSection(JTS);
283 for (unsigned JTI = 0; JTI < JT.size(); JTI++) {
284 ArrayRef<MachineBasicBlock *> JTBBs = JT[JTI].MBBs;
285 if (JTBBs.empty())
286 continue;
287
288 MCSymbol *JTStart = getJTPublicSymbol(JTI);
289 OutStreamer->emitLabel(JTStart);
290 for (const MachineBasicBlock *MBB : JTBBs) {
291 const MCExpr *Diff = MCBinaryExpr::createSub(
294 OutStreamer->emitValue(Diff, EntrySize);
295 }
296 const MCExpr *JTSize =
297 MCConstantExpr::create(JTBBs.size() * EntrySize, OutContext);
298 OutStreamer->emitELFSize(JTStart, JTSize);
299 }
300}
301
302char BPFAsmPrinter::ID = 0;
303
304INITIALIZE_PASS(BPFAsmPrinter, "bpf-asm-printer", "BPF Assembly Printer", false,
305 false)
306
307// Force static initialization.
309LLVMInitializeBPFAsmPrinter() {
313}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
#define BPF_TRAP
Definition BPF.h:25
This file contains support for writing BTF debug info.
#define X(NUM, ENUM, NAME)
Definition ELF.h:851
#define LLVM_ABI
Definition Compiler.h:213
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:137
const TargetLoweringObjectFile & getObjFileLowering() const
Return information about object file lowering.
MCSymbol * getSymbol(const GlobalValue *GV) const
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
TargetMachine & TM
Target machine description.
Definition AsmPrinter.h:94
const MCAsmInfo * MAI
Target Asm Printer information.
Definition AsmPrinter.h:97
SmallVector< std::unique_ptr< AsmPrinterHandler >, 2 > Handlers
Definition AsmPrinter.h:244
MachineFunction * MF
The current machine function.
Definition AsmPrinter.h:109
bool doInitialization(Module &M) override
Set up the AsmPrinter when we are working on a new module.
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition AsmPrinter.h:101
bool doFinalization(Module &M) override
Shut down the asmprinter.
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:106
MCSymbol * GetBlockAddressSymbol(const BlockAddress *BA) const
Return the MCSymbol used to satisfy BlockAddress uses of the specified basic block.
const DataLayout & getDataLayout() const
Return information about data layout.
MCSymbol * GetExternalSymbolSymbol(const Twine &Sym) const
Return the MCSymbol for the specified ExternalSymbol.
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
MCSymbol * getJTPublicSymbol(unsigned JTI)
void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O)
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, const char *ExtraCode, raw_ostream &O) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
bool doFinalization(Module &M) override
Shut down the asmprinter.
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) override
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
void emitFunctionBodyEnd() override
Targets can override this to emit stuff after the last basic block in the function.
bool doInitialization(Module &M) override
Set up the AsmPrinter when we are working on a new module.
void emitJumpTableInfo() override
Print assembly representations of the jump tables used by the current function to the current output ...
void emitInstruction(const MachineInstr *MI) override
Targets should implement this to emit instructions.
static const char * getRegisterName(MCRegister Reg)
void Lower(const MachineInstr *MI, MCInst &OutMI) const
bool hasGotox() const
Collect and emit BTF information.
Definition BTFDebug.h:289
ConstantArray - Constant Array Declarations.
Definition Constants.h:576
This is an important base class in LLVM.
Definition Constant.h:43
Diagnostic information for unsupported feature in backend.
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:428
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Context object for machine code objects.
Definition MCContext.h:83
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition MCSection.h:569
MCSymbol * getBeginSymbol()
Definition MCSection.h:642
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
Representation of each machine instruction.
LLVM_ABI unsigned getEntrySize(const DataLayout &TD) const
getEntrySize - Return the size of each entry in the jump table.
@ EK_BlockAddress
EK_BlockAddress - Each entry is a plain address of block, e.g.: .word LBB123.
const std::vector< MachineJumpTableEntry > & getJumpTables() const
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
const BlockAddress * getBlockAddress() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ MO_GlobalAddress
Address of a global value.
@ MO_BlockAddress
Address of a basic block.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
virtual MCSection * getSectionForJumpTable(const Function &F, const TargetMachine &TM) const
Value * getOperand(unsigned i) const
Definition User.h:207
unsigned getNumOperands() const
Definition User.h:229
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SHF_ALLOC
Definition ELF.h:1249
@ SHT_PROGBITS
Definition ELF.h:1148
@ STB_GLOBAL
Definition ELF.h:1406
@ STT_OBJECT
Definition ELF.h:1418
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
Target & getTheBPFleTarget()
Target & getTheBPFbeTarget()
Target & getTheBPFTarget()
@ Global
Append to llvm.global_dtors.
DWARFExpression::Operation Op
This structure is used to retain landing pad info for the current function.
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...