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