xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/BPF/BPFCheckAndAdjustIR.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
1*e8d8bef9SDimitry Andric //===------------ BPFCheckAndAdjustIR.cpp - Check and Adjust IR -----------===//
2*e8d8bef9SDimitry Andric //
3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e8d8bef9SDimitry Andric //
7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8*e8d8bef9SDimitry Andric //
9*e8d8bef9SDimitry Andric // Check IR and adjust IR for verifier friendly codes.
10*e8d8bef9SDimitry Andric // The following are done for IR checking:
11*e8d8bef9SDimitry Andric //   - no relocation globals in PHI node.
12*e8d8bef9SDimitry Andric // The following are done for IR adjustment:
13*e8d8bef9SDimitry Andric //   - remove __builtin_bpf_passthrough builtins. Target independent IR
14*e8d8bef9SDimitry Andric //     optimizations are done and those builtins can be removed.
15*e8d8bef9SDimitry Andric //
16*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
17*e8d8bef9SDimitry Andric 
18*e8d8bef9SDimitry Andric #include "BPF.h"
19*e8d8bef9SDimitry Andric #include "BPFCORE.h"
20*e8d8bef9SDimitry Andric #include "BPFTargetMachine.h"
21*e8d8bef9SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
22*e8d8bef9SDimitry Andric #include "llvm/IR/GlobalVariable.h"
23*e8d8bef9SDimitry Andric #include "llvm/IR/Instruction.h"
24*e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
25*e8d8bef9SDimitry Andric #include "llvm/IR/Module.h"
26*e8d8bef9SDimitry Andric #include "llvm/IR/Type.h"
27*e8d8bef9SDimitry Andric #include "llvm/IR/User.h"
28*e8d8bef9SDimitry Andric #include "llvm/IR/Value.h"
29*e8d8bef9SDimitry Andric #include "llvm/Pass.h"
30*e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
31*e8d8bef9SDimitry Andric 
32*e8d8bef9SDimitry Andric #define DEBUG_TYPE "bpf-check-and-opt-ir"
33*e8d8bef9SDimitry Andric 
34*e8d8bef9SDimitry Andric using namespace llvm;
35*e8d8bef9SDimitry Andric 
36*e8d8bef9SDimitry Andric namespace {
37*e8d8bef9SDimitry Andric 
38*e8d8bef9SDimitry Andric class BPFCheckAndAdjustIR final : public ModulePass {
39*e8d8bef9SDimitry Andric   bool runOnModule(Module &F) override;
40*e8d8bef9SDimitry Andric 
41*e8d8bef9SDimitry Andric public:
42*e8d8bef9SDimitry Andric   static char ID;
43*e8d8bef9SDimitry Andric   BPFCheckAndAdjustIR() : ModulePass(ID) {}
44*e8d8bef9SDimitry Andric 
45*e8d8bef9SDimitry Andric private:
46*e8d8bef9SDimitry Andric   void checkIR(Module &M);
47*e8d8bef9SDimitry Andric   bool adjustIR(Module &M);
48*e8d8bef9SDimitry Andric   bool removePassThroughBuiltin(Module &M);
49*e8d8bef9SDimitry Andric };
50*e8d8bef9SDimitry Andric } // End anonymous namespace
51*e8d8bef9SDimitry Andric 
52*e8d8bef9SDimitry Andric char BPFCheckAndAdjustIR::ID = 0;
53*e8d8bef9SDimitry Andric INITIALIZE_PASS(BPFCheckAndAdjustIR, DEBUG_TYPE, "BPF Check And Adjust IR",
54*e8d8bef9SDimitry Andric                 false, false)
55*e8d8bef9SDimitry Andric 
56*e8d8bef9SDimitry Andric ModulePass *llvm::createBPFCheckAndAdjustIR() {
57*e8d8bef9SDimitry Andric   return new BPFCheckAndAdjustIR();
58*e8d8bef9SDimitry Andric }
59*e8d8bef9SDimitry Andric 
60*e8d8bef9SDimitry Andric void BPFCheckAndAdjustIR::checkIR(Module &M) {
61*e8d8bef9SDimitry Andric   // Ensure relocation global won't appear in PHI node
62*e8d8bef9SDimitry Andric   // This may happen if the compiler generated the following code:
63*e8d8bef9SDimitry Andric   //   B1:
64*e8d8bef9SDimitry Andric   //      g1 = @llvm.skb_buff:0:1...
65*e8d8bef9SDimitry Andric   //      ...
66*e8d8bef9SDimitry Andric   //      goto B_COMMON
67*e8d8bef9SDimitry Andric   //   B2:
68*e8d8bef9SDimitry Andric   //      g2 = @llvm.skb_buff:0:2...
69*e8d8bef9SDimitry Andric   //      ...
70*e8d8bef9SDimitry Andric   //      goto B_COMMON
71*e8d8bef9SDimitry Andric   //   B_COMMON:
72*e8d8bef9SDimitry Andric   //      g = PHI(g1, g2)
73*e8d8bef9SDimitry Andric   //      x = load g
74*e8d8bef9SDimitry Andric   //      ...
75*e8d8bef9SDimitry Andric   // If anything likes the above "g = PHI(g1, g2)", issue a fatal error.
76*e8d8bef9SDimitry Andric   for (Function &F : M)
77*e8d8bef9SDimitry Andric     for (auto &BB : F)
78*e8d8bef9SDimitry Andric       for (auto &I : BB) {
79*e8d8bef9SDimitry Andric         PHINode *PN = dyn_cast<PHINode>(&I);
80*e8d8bef9SDimitry Andric         if (!PN || PN->use_empty())
81*e8d8bef9SDimitry Andric           continue;
82*e8d8bef9SDimitry Andric         for (int i = 0, e = PN->getNumIncomingValues(); i < e; ++i) {
83*e8d8bef9SDimitry Andric           auto *GV = dyn_cast<GlobalVariable>(PN->getIncomingValue(i));
84*e8d8bef9SDimitry Andric           if (!GV)
85*e8d8bef9SDimitry Andric             continue;
86*e8d8bef9SDimitry Andric           if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) ||
87*e8d8bef9SDimitry Andric               GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr))
88*e8d8bef9SDimitry Andric             report_fatal_error("relocation global in PHI node");
89*e8d8bef9SDimitry Andric         }
90*e8d8bef9SDimitry Andric       }
91*e8d8bef9SDimitry Andric }
92*e8d8bef9SDimitry Andric 
93*e8d8bef9SDimitry Andric bool BPFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) {
94*e8d8bef9SDimitry Andric   // Remove __builtin_bpf_passthrough()'s which are used to prevent
95*e8d8bef9SDimitry Andric   // certain IR optimizations. Now major IR optimizations are done,
96*e8d8bef9SDimitry Andric   // remove them.
97*e8d8bef9SDimitry Andric   bool Changed = false;
98*e8d8bef9SDimitry Andric   CallInst *ToBeDeleted = nullptr;
99*e8d8bef9SDimitry Andric   for (Function &F : M)
100*e8d8bef9SDimitry Andric     for (auto &BB : F)
101*e8d8bef9SDimitry Andric       for (auto &I : BB) {
102*e8d8bef9SDimitry Andric         if (ToBeDeleted) {
103*e8d8bef9SDimitry Andric           ToBeDeleted->eraseFromParent();
104*e8d8bef9SDimitry Andric           ToBeDeleted = nullptr;
105*e8d8bef9SDimitry Andric         }
106*e8d8bef9SDimitry Andric 
107*e8d8bef9SDimitry Andric         auto *Call = dyn_cast<CallInst>(&I);
108*e8d8bef9SDimitry Andric         if (!Call)
109*e8d8bef9SDimitry Andric           continue;
110*e8d8bef9SDimitry Andric         auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
111*e8d8bef9SDimitry Andric         if (!GV)
112*e8d8bef9SDimitry Andric           continue;
113*e8d8bef9SDimitry Andric         if (!GV->getName().startswith("llvm.bpf.passthrough"))
114*e8d8bef9SDimitry Andric           continue;
115*e8d8bef9SDimitry Andric         Changed = true;
116*e8d8bef9SDimitry Andric         Value *Arg = Call->getArgOperand(1);
117*e8d8bef9SDimitry Andric         Call->replaceAllUsesWith(Arg);
118*e8d8bef9SDimitry Andric         ToBeDeleted = Call;
119*e8d8bef9SDimitry Andric       }
120*e8d8bef9SDimitry Andric   return Changed;
121*e8d8bef9SDimitry Andric }
122*e8d8bef9SDimitry Andric 
123*e8d8bef9SDimitry Andric bool BPFCheckAndAdjustIR::adjustIR(Module &M) {
124*e8d8bef9SDimitry Andric   return removePassThroughBuiltin(M);
125*e8d8bef9SDimitry Andric }
126*e8d8bef9SDimitry Andric 
127*e8d8bef9SDimitry Andric bool BPFCheckAndAdjustIR::runOnModule(Module &M) {
128*e8d8bef9SDimitry Andric   checkIR(M);
129*e8d8bef9SDimitry Andric   return adjustIR(M);
130*e8d8bef9SDimitry Andric }
131