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