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