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 "BPF.h" |
15 | #include "BPFInstrInfo.h" |
16 | #include "BPFMCInstLower.h" |
17 | #include "BPFTargetMachine.h" |
18 | #include "BTFDebug.h" |
19 | #include "MCTargetDesc/BPFInstPrinter.h" |
20 | #include "TargetInfo/BPFTargetInfo.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/IR/Module.h" |
27 | #include "llvm/MC/MCAsmInfo.h" |
28 | #include "llvm/MC/MCInst.h" |
29 | #include "llvm/MC/MCStreamer.h" |
30 | #include "llvm/MC/MCSymbol.h" |
31 | #include "llvm/MC/TargetRegistry.h" |
32 | #include "llvm/Support/raw_ostream.h" |
33 | using namespace llvm; |
34 | |
35 | #define DEBUG_TYPE "asm-printer" |
36 | |
37 | namespace { |
38 | class BPFAsmPrinter : public AsmPrinter { |
39 | public: |
40 | explicit BPFAsmPrinter(TargetMachine &TM, |
41 | std::unique_ptr<MCStreamer> Streamer) |
42 | : AsmPrinter(TM, std::move(Streamer)), BTF(nullptr) {} |
43 | |
44 | StringRef getPassName() const override { return "BPF Assembly Printer" ; } |
45 | bool doInitialization(Module &M) override; |
46 | void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); |
47 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
48 | const char *, raw_ostream &O) override; |
49 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, |
50 | const char *, raw_ostream &O) override; |
51 | |
52 | void emitInstruction(const MachineInstr *MI) override; |
53 | |
54 | private: |
55 | BTFDebug *BTF; |
56 | }; |
57 | } // namespace |
58 | |
59 | bool BPFAsmPrinter::doInitialization(Module &M) { |
60 | AsmPrinter::doInitialization(M); |
61 | |
62 | // Only emit BTF when debuginfo available. |
63 | if (MAI->doesSupportDebugInformation() && !M.debug_compile_units().empty()) { |
64 | BTF = new BTFDebug(this); |
65 | DebugHandlers.push_back(Elt: std::unique_ptr<BTFDebug>(BTF)); |
66 | } |
67 | |
68 | return false; |
69 | } |
70 | |
71 | void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, |
72 | raw_ostream &O) { |
73 | const MachineOperand &MO = MI->getOperand(i: OpNum); |
74 | |
75 | switch (MO.getType()) { |
76 | case MachineOperand::MO_Register: |
77 | O << BPFInstPrinter::getRegisterName(Reg: MO.getReg()); |
78 | break; |
79 | |
80 | case MachineOperand::MO_Immediate: |
81 | O << MO.getImm(); |
82 | break; |
83 | |
84 | case MachineOperand::MO_MachineBasicBlock: |
85 | O << *MO.getMBB()->getSymbol(); |
86 | break; |
87 | |
88 | case MachineOperand::MO_GlobalAddress: |
89 | O << *getSymbol(GV: MO.getGlobal()); |
90 | break; |
91 | |
92 | case MachineOperand::MO_BlockAddress: { |
93 | MCSymbol *BA = GetBlockAddressSymbol(BA: MO.getBlockAddress()); |
94 | O << BA->getName(); |
95 | break; |
96 | } |
97 | |
98 | case MachineOperand::MO_ExternalSymbol: |
99 | O << *GetExternalSymbolSymbol(Sym: MO.getSymbolName()); |
100 | break; |
101 | |
102 | case MachineOperand::MO_JumpTableIndex: |
103 | case MachineOperand::MO_ConstantPoolIndex: |
104 | default: |
105 | llvm_unreachable("<unknown operand type>" ); |
106 | } |
107 | } |
108 | |
109 | bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
110 | const char *, raw_ostream &O) { |
111 | if (ExtraCode && ExtraCode[0]) |
112 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
113 | |
114 | printOperand(MI, OpNum: OpNo, O); |
115 | return false; |
116 | } |
117 | |
118 | bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
119 | unsigned OpNum, const char *, |
120 | raw_ostream &O) { |
121 | assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands" ); |
122 | const MachineOperand &BaseMO = MI->getOperand(i: OpNum); |
123 | const MachineOperand &OffsetMO = MI->getOperand(i: OpNum + 1); |
124 | assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand." ); |
125 | assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand." ); |
126 | int Offset = OffsetMO.getImm(); |
127 | |
128 | if (ExtraCode) |
129 | return true; // Unknown modifier. |
130 | |
131 | if (Offset < 0) |
132 | O << "(" << BPFInstPrinter::getRegisterName(Reg: BaseMO.getReg()) << " - " << -Offset << ")" ; |
133 | else |
134 | O << "(" << BPFInstPrinter::getRegisterName(Reg: BaseMO.getReg()) << " + " << Offset << ")" ; |
135 | |
136 | return false; |
137 | } |
138 | |
139 | void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) { |
140 | BPF_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
141 | Features: getSubtargetInfo().getFeatureBits()); |
142 | |
143 | MCInst TmpInst; |
144 | |
145 | if (!BTF || !BTF->InstLower(MI, OutMI&: TmpInst)) { |
146 | BPFMCInstLower MCInstLowering(OutContext, *this); |
147 | MCInstLowering.Lower(MI, OutMI&: TmpInst); |
148 | } |
149 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
150 | } |
151 | |
152 | // Force static initialization. |
153 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmPrinter() { |
154 | RegisterAsmPrinter<BPFAsmPrinter> X(getTheBPFleTarget()); |
155 | RegisterAsmPrinter<BPFAsmPrinter> Y(getTheBPFbeTarget()); |
156 | RegisterAsmPrinter<BPFAsmPrinter> Z(getTheBPFTarget()); |
157 | } |
158 | |