1 //===-- BPFASpaceCastSimplifyPass.cpp - BPF addrspacecast simplications --===// 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 #include "BPF.h" 10 #include <optional> 11 12 #define DEBUG_TYPE "bpf-aspace-simplify" 13 14 using namespace llvm; 15 16 namespace { 17 18 struct CastGEPCast { 19 AddrSpaceCastInst *OuterCast; 20 21 // Match chain of instructions: 22 // %inner = addrspacecast N->M 23 // %gep = getelementptr %inner, ... 24 // %outer = addrspacecast M->N %gep 25 // Where I is %outer. 26 static std::optional<CastGEPCast> match(Value *I) { 27 auto *OuterCast = dyn_cast<AddrSpaceCastInst>(I); 28 if (!OuterCast) 29 return std::nullopt; 30 auto *GEP = dyn_cast<GetElementPtrInst>(OuterCast->getPointerOperand()); 31 if (!GEP) 32 return std::nullopt; 33 auto *InnerCast = dyn_cast<AddrSpaceCastInst>(GEP->getPointerOperand()); 34 if (!InnerCast) 35 return std::nullopt; 36 if (InnerCast->getSrcAddressSpace() != OuterCast->getDestAddressSpace()) 37 return std::nullopt; 38 if (InnerCast->getDestAddressSpace() != OuterCast->getSrcAddressSpace()) 39 return std::nullopt; 40 return CastGEPCast{OuterCast}; 41 } 42 43 static PointerType *changeAddressSpace(PointerType *Ty, unsigned AS) { 44 return Ty->get(Ty->getContext(), AS); 45 } 46 47 // Assuming match(this->OuterCast) is true, convert: 48 // (addrspacecast M->N (getelementptr (addrspacecast N->M ptr) ...)) 49 // To: 50 // (getelementptr ptr ...) 51 GetElementPtrInst *rewrite() { 52 auto *GEP = cast<GetElementPtrInst>(OuterCast->getPointerOperand()); 53 auto *InnerCast = cast<AddrSpaceCastInst>(GEP->getPointerOperand()); 54 unsigned AS = OuterCast->getDestAddressSpace(); 55 auto *NewGEP = cast<GetElementPtrInst>(GEP->clone()); 56 NewGEP->setName(GEP->getName()); 57 NewGEP->insertAfter(OuterCast); 58 NewGEP->setOperand(0, InnerCast->getPointerOperand()); 59 auto *GEPTy = cast<PointerType>(GEP->getType()); 60 NewGEP->mutateType(changeAddressSpace(GEPTy, AS)); 61 OuterCast->replaceAllUsesWith(NewGEP); 62 OuterCast->eraseFromParent(); 63 if (GEP->use_empty()) 64 GEP->eraseFromParent(); 65 if (InnerCast->use_empty()) 66 InnerCast->eraseFromParent(); 67 return NewGEP; 68 } 69 }; 70 71 } // anonymous namespace 72 73 PreservedAnalyses BPFASpaceCastSimplifyPass::run(Function &F, 74 FunctionAnalysisManager &AM) { 75 SmallVector<CastGEPCast, 16> WorkList; 76 bool Changed = false; 77 for (BasicBlock &BB : F) { 78 for (Instruction &I : BB) 79 if (auto It = CastGEPCast::match(&I)) 80 WorkList.push_back(It.value()); 81 Changed |= !WorkList.empty(); 82 83 while (!WorkList.empty()) { 84 CastGEPCast InsnChain = WorkList.pop_back_val(); 85 GetElementPtrInst *NewGEP = InsnChain.rewrite(); 86 for (User *U : NewGEP->users()) 87 if (auto It = CastGEPCast::match(U)) 88 WorkList.push_back(It.value()); 89 } 90 } 91 return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); 92 } 93