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