xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFASpaceCastSimplifyPass.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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.
match__anon7c7084c10111::CastGEPCast26   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 
changeAddressSpace__anon7c7084c10111::CastGEPCast43   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 ...)
rewrite__anon7c7084c10111::CastGEPCast51   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 
run(Function & F,FunctionAnalysisManager & AM)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