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