| //===-- 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 <optional> |
| |
| #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<CastGEPCast> match(Value *I) { |
| auto *OuterCast = dyn_cast<AddrSpaceCastInst>(I); |
| if (!OuterCast) |
| return std::nullopt; |
| auto *GEP = dyn_cast<GetElementPtrInst>(OuterCast->getPointerOperand()); |
| if (!GEP) |
| return std::nullopt; |
| auto *InnerCast = dyn_cast<AddrSpaceCastInst>(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<GetElementPtrInst>(OuterCast->getPointerOperand()); |
| auto *InnerCast = cast<AddrSpaceCastInst>(GEP->getPointerOperand()); |
| unsigned AS = OuterCast->getDestAddressSpace(); |
| auto *NewGEP = cast<GetElementPtrInst>(GEP->clone()); |
| NewGEP->setName(GEP->getName()); |
| NewGEP->insertAfter(OuterCast->getIterator()); |
| NewGEP->setOperand(0, InnerCast->getPointerOperand()); |
| auto *GEPTy = cast<PointerType>(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<CastGEPCast, 16> 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(); |
| } |