LLVM 24.0.0git
LogicalSROA.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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/// \file
9/// This transformation implements the well known scalar replacement of
10/// aggregates transformation but for logical pointers.
11/// It tries to identify promotable elements of an aggregate alloca, and
12/// promote them to multiple allocas of scalar type.
13///
14/// FIXME: nested aggregates are not fully optimized (#192619).
15/// FIXME: array are not optimized (#192620).
16///
17//===----------------------------------------------------------------------===//
18
20#include "llvm/ADT/DenseSet.h"
22#include "llvm/IR/IRBuilder.h"
24#include "llvm/IR/PassManager.h"
25#include "llvm/Pass.h"
27
28using namespace llvm;
29
30#define DEBUG_TYPE "logical-sroa"
31
32// Return all lifetime intrinsics with the instruction I as operand.
36
37 for (User *U : I.users()) {
38 if (auto *LI = dyn_cast<LifetimeIntrinsic>(U))
39 Output.push_back(LI);
40 }
41
42 return Output;
43}
44
45// Returns true if all direct and indirect users of the alloca
46// allow the split.
48 SmallVector<Value *> WorkList(SAI.users());
49 DenseSet<Value *> Visited;
50
51 // Helper function to enqueue all non-visited users of `I`.
52 auto enqueueAllUsers = [&](Instruction *I) {
53 for (auto *U : I->users()) {
54 if (Visited.contains(U))
55 continue;
56 WorkList.push_back(U);
57 }
58 };
59
60 while (!WorkList.empty()) {
62 WorkList.pop_back();
63
64 // User is not an instruction. Not sure what it it, in
65 // doubt, don't split.
66 if (!I)
67 return false;
68
69 Visited.insert(I);
70
71 // Those allow the alloca split.
73 continue;
74
75 // If we load the whole alloca, we cannot split,
76 // otherwise, we can stop looking into derived users.
77 if (auto *LI = dyn_cast<LoadInst>(I)) {
78 if (LI->getPointerOperand() == &SAI)
79 return false;
80 continue;
81 }
82
83 // If we store to whole alloca, we cannot split,
84 // otherwise, we can stop looking into derived users.
85 if (auto *SI = dyn_cast<StoreInst>(I)) {
86 if (SI->getPointerOperand() == &SAI)
87 return false;
88 continue;
89 }
90
91 // PHI and Select instruction are not inherently preventing
92 // the split, but correctly handling those requires more testing,
93 // so postponing this (See #193749)
95 return false;
96
97 if (auto *SGEP = dyn_cast<StructuredGEPInst>(I)) {
98 // If the SGEP has no indices and is still there, this probably means the
99 // ptr is escaping or uses as-is. For now, we bail out.
100 if (SGEP->getNumIndices() == 0)
101 return false;
102
103 enqueueAllUsers(SGEP);
104 continue;
105 }
106
107 // Any other users prevents the split (call, escape, etc).
108 return false;
109 }
110
111 return true;
112}
113
114// Returns a vector with one element for each field of the struct allocated by
115// SAI. Each element is a vector of SGEP instruction referencing this field.
116// This function ignores lifetime intrinsics.
120 SmallVector<SmallVector<StructuredGEPInst *>> Output(ST->getNumElements());
121
122 for (User *U : SAI.users()) {
124 continue;
125
126 auto *SGEP = cast<StructuredGEPInst>(U);
127
128 // IR rule: SGEP on struct can only use constant int as indices.
129 ConstantInt *Index = cast<ConstantInt>(SGEP->getIndexOperand(0));
130 assert(Index->getZExtValue() < Output.size());
131 Output[Index->getZExtValue()].push_back(SGEP);
132 }
133
134 return Output;
135}
136
137// For each lifetime intrinsic in LifetimeIntrinsics, creates a new one, but
138// uses V as operand.
140 Value *V) {
141 B.SetInsertPoint(II);
142
143 if (II->getIntrinsicID() == Intrinsic::lifetime_start) {
144 B.CreateLifetimeStart(V);
145 } else if (II->getIntrinsicID() == Intrinsic::lifetime_end) {
146 B.CreateLifetimeEnd(V);
147 } else
148 llvm_unreachable("invalid argument: expected a lifetime intrinsic");
149}
150
152 StructuredAllocaInst *FieldAlloca) {
153 if (SGEP->getNumIndices() == 1) {
154 SGEP->replaceAllUsesWith(FieldAlloca);
155 SGEP->eraseFromParent();
156 return;
157 }
158
160 B.SetInsertPoint(SGEP);
161 auto *I = B.CreateStructuredGEP(FieldAlloca->getAllocationType(), FieldAlloca,
162 Indices, SGEP->getName());
163 SGEP->replaceAllUsesWith(I);
164 SGEP->eraseFromParent();
165}
166
168 // For now, LogicalSROA only handles SGEP on structs.
170 if (!ST)
171 return false;
172
173 if (!isAllocaSplittable(SAI))
174 return false;
175
176 auto PerFieldSGEP = collectPerFieldSGEP(SAI);
177 assert(PerFieldSGEP.size() == ST->getNumElements());
178
179 auto LifetimeIntrinsics = collectLifetimeIntrinsicsUsing(SAI);
180 IRBuilder B(&SAI);
181 for (const auto &[FieldIndex, Users] : llvm::enumerate(PerFieldSGEP)) {
182 if (Users.empty())
183 continue;
184
185 B.SetInsertPoint(&SAI);
186 auto *FieldAlloca = cast<StructuredAllocaInst>(
187 B.CreateStructuredAlloca(ST->getElementType(FieldIndex)));
188
189 for (auto II : LifetimeIntrinsics)
190 copyLifetimeIntrinsicFor(B, II, FieldAlloca);
191
192 for (StructuredGEPInst *SGEP : Users)
193 rewriteSGEPChain(B, SGEP, FieldAlloca);
194 }
195
196 for (auto *II : LifetimeIntrinsics)
197 II->eraseFromParent();
198 SAI.eraseFromParent();
199 return true;
200}
201
202static bool runLogicalSROA(Function &F) {
204 BasicBlock &EntryBB = F.getEntryBlock();
205 for (Instruction &I : EntryBB) {
207 Worklist.push_back(SAI);
208 }
209
210 bool Changed = false;
211 for (StructuredAllocaInst *SAI : Worklist)
213 return Changed;
214}
215
225
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
This header defines various interfaces for pass management in LLVM.
iv Induction Variable Users
Definition IVUsers.cpp:48
static bool runLogicalSROA(Function &F)
static SmallVector< LifetimeIntrinsic * > collectLifetimeIntrinsicsUsing(Instruction &I)
static bool runOnStructuredAlloca(StructuredAllocaInst &SAI)
static void rewriteSGEPChain(IRBuilder<> &B, StructuredGEPInst *SGEP, StructuredAllocaInst *FieldAlloca)
static SmallVector< SmallVector< StructuredGEPInst * > > collectPerFieldSGEP(StructuredAllocaInst &SAI)
static bool isAllocaSplittable(StructuredAllocaInst &SAI)
static void copyLifetimeIntrinsicFor(IRBuilder<> &B, LifetimeIntrinsic *II, Value *V)
This file provides the interface for LLVM's Logical Scalar Replacement of Aggregates pass.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
This file defines the SmallVector class.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
This is the shared class of boolean and integer constants.
Definition Constants.h:87
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2903
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
This is the common base class for lifetime intrinsics.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Run the pass over the function.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Class to represent struct types.
iterator_range< op_iterator > indices()
unsigned getNumIndices() const
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
iterator_range< user_iterator > users()
Definition Value.h:426
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:315
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.