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