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