//===-- BPFASpaceCastSimplifyPass.cpp - BPF addrspacecast simplications --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "BPF.h" #include #define DEBUG_TYPE "bpf-aspace-simplify" using namespace llvm; namespace { struct CastGEPCast { AddrSpaceCastInst *OuterCast; // Match chain of instructions: // %inner = addrspacecast N->M // %gep = getelementptr %inner, ... // %outer = addrspacecast M->N %gep // Where I is %outer. static std::optional match(Value *I) { auto *OuterCast = dyn_cast(I); if (!OuterCast) return std::nullopt; auto *GEP = dyn_cast(OuterCast->getPointerOperand()); if (!GEP) return std::nullopt; auto *InnerCast = dyn_cast(GEP->getPointerOperand()); if (!InnerCast) return std::nullopt; if (InnerCast->getSrcAddressSpace() != OuterCast->getDestAddressSpace()) return std::nullopt; if (InnerCast->getDestAddressSpace() != OuterCast->getSrcAddressSpace()) return std::nullopt; return CastGEPCast{OuterCast}; } static PointerType *changeAddressSpace(PointerType *Ty, unsigned AS) { return Ty->get(Ty->getContext(), AS); } // Assuming match(this->OuterCast) is true, convert: // (addrspacecast M->N (getelementptr (addrspacecast N->M ptr) ...)) // To: // (getelementptr ptr ...) GetElementPtrInst *rewrite() { auto *GEP = cast(OuterCast->getPointerOperand()); auto *InnerCast = cast(GEP->getPointerOperand()); unsigned AS = OuterCast->getDestAddressSpace(); auto *NewGEP = cast(GEP->clone()); NewGEP->setName(GEP->getName()); NewGEP->insertAfter(OuterCast); NewGEP->setOperand(0, InnerCast->getPointerOperand()); auto *GEPTy = cast(GEP->getType()); NewGEP->mutateType(changeAddressSpace(GEPTy, AS)); OuterCast->replaceAllUsesWith(NewGEP); OuterCast->eraseFromParent(); if (GEP->use_empty()) GEP->eraseFromParent(); if (InnerCast->use_empty()) InnerCast->eraseFromParent(); return NewGEP; } }; } // anonymous namespace PreservedAnalyses BPFASpaceCastSimplifyPass::run(Function &F, FunctionAnalysisManager &AM) { SmallVector WorkList; bool Changed = false; for (BasicBlock &BB : F) { for (Instruction &I : BB) if (auto It = CastGEPCast::match(&I)) WorkList.push_back(It.value()); Changed |= !WorkList.empty(); while (!WorkList.empty()) { CastGEPCast InsnChain = WorkList.pop_back_val(); GetElementPtrInst *NewGEP = InsnChain.rewrite(); for (User *U : NewGEP->users()) if (auto It = CastGEPCast::match(U)) WorkList.push_back(It.value()); } } return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); }