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"
23#include "llvm/IR/IRBuilder.h"
25#include "llvm/IR/PassManager.h"
27#include "llvm/Pass.h"
29
30using namespace llvm;
31
32#define DEBUG_TYPE "logical-sroa"
33
34// Return all lifetime intrinsics with the instruction I as operand.
38
39 for (User *U : I.users()) {
40 if (auto *LI = dyn_cast<LifetimeIntrinsic>(U))
41 Output.push_back(LI);
42 }
43
44 return Output;
45}
46
47// Returns true if all direct and indirect users of the alloca
48// allow the split.
50 SmallVector<Value *> WorkList(SAI.users());
51 DenseSet<Value *> Visited;
52
53 // Helper function to enqueue all non-visited users of `I`.
54 auto enqueueAllUsers = [&](Instruction *I) {
55 for (auto *U : I->users()) {
56 if (Visited.contains(U))
57 continue;
58 WorkList.push_back(U);
59 }
60 };
61
62 while (!WorkList.empty()) {
64 WorkList.pop_back();
65
66 // User is not an instruction. Not sure what it it, in
67 // doubt, don't split.
68 if (!I)
69 return false;
70
71 Visited.insert(I);
72
73 // Those allow the alloca split.
75 continue;
76
77 // If we load the whole alloca, we cannot split,
78 // otherwise, we can stop looking into derived users.
79 if (auto *LI = dyn_cast<LoadInst>(I)) {
80 if (LI->getPointerOperand() == &SAI)
81 return false;
82 continue;
83 }
84
85 // If we store to whole alloca, we cannot split,
86 // otherwise, we can stop looking into derived users.
87 if (auto *SI = dyn_cast<StoreInst>(I)) {
88 if (SI->getPointerOperand() == &SAI)
89 return false;
90 continue;
91 }
92
93 // PHI and Select instruction are not inherently preventing
94 // the split, but correctly handling those requires more testing,
95 // so postponing this (See #193749)
97 return false;
98
99 if (auto *SGEP = dyn_cast<StructuredGEPInst>(I)) {
100 // If the SGEP has no indices and is still there, this probably means the
101 // ptr is escaping or uses as-is. For now, we bail out.
102 if (SGEP->getNumIndices() == 0)
103 return false;
104
105 enqueueAllUsers(SGEP);
106 continue;
107 }
108
109 // Any other users prevents the split (call, escape, etc).
110 return false;
111 }
112
113 return true;
114}
115
116// Returns a vector with one element for each field of the struct allocated by
117// SAI. Each element is a vector of SGEP instruction referencing this field.
118// This function ignores lifetime intrinsics.
122 SmallVector<SmallVector<StructuredGEPInst *>> Output(ST->getNumElements());
123
124 for (User *U : SAI.users()) {
126 continue;
127
128 auto *SGEP = cast<StructuredGEPInst>(U);
129
130 // IR rule: SGEP on struct can only use constant int as indices.
131 ConstantInt *Index = cast<ConstantInt>(SGEP->getIndexOperand(0));
132 assert(Index->getZExtValue() < Output.size());
133 Output[Index->getZExtValue()].push_back(SGEP);
134 }
135
136 return Output;
137}
138
139// For each lifetime intrinsic in LifetimeIntrinsics, creates a new one, but
140// uses V as operand.
142 Value *V) {
143 B.SetInsertPoint(II);
144
145 if (II->getIntrinsicID() == Intrinsic::lifetime_start) {
146 B.CreateLifetimeStart(V);
147 } else if (II->getIntrinsicID() == Intrinsic::lifetime_end) {
148 B.CreateLifetimeEnd(V);
149 } else
150 llvm_unreachable("invalid argument: expected a lifetime intrinsic");
151}
152
154 StructuredAllocaInst *FieldAlloca) {
155 if (SGEP->getNumIndices() == 1) {
156 SGEP->replaceAllUsesWith(FieldAlloca);
157 SGEP->eraseFromParent();
158 return;
159 }
160
162 B.SetInsertPoint(SGEP);
163 auto *I = B.CreateStructuredGEP(FieldAlloca->getAllocationType(), FieldAlloca,
164 Indices, SGEP->getName());
165 SGEP->replaceAllUsesWith(I);
166 SGEP->eraseFromParent();
167}
168
170 // For now, LogicalSROA only handles SGEP on structs.
172 if (!ST)
173 return false;
174
175 if (!isAllocaSplittable(SAI))
176 return false;
177
178 auto PerFieldSGEP = collectPerFieldSGEP(SAI);
179 assert(PerFieldSGEP.size() == ST->getNumElements());
180
181 auto LifetimeIntrinsics = collectLifetimeIntrinsicsUsing(SAI);
182 IRBuilder B(&SAI);
183 for (const auto &[FieldIndex, Users] : llvm::enumerate(PerFieldSGEP)) {
184 if (Users.empty())
185 continue;
186
187 B.SetInsertPoint(&SAI);
188 auto *FieldAlloca = cast<StructuredAllocaInst>(
189 B.CreateStructuredAlloca(ST->getElementType(FieldIndex)));
190
191 for (auto II : LifetimeIntrinsics)
192 copyLifetimeIntrinsicFor(B, II, FieldAlloca);
193
194 for (StructuredGEPInst *SGEP : Users)
195 rewriteSGEPChain(B, SGEP, FieldAlloca);
196 }
197
198 for (auto *II : LifetimeIntrinsics)
199 II->eraseFromParent();
200 SAI.eraseFromParent();
201 return true;
202}
203
204static bool runLogicalSROA(Function &F) {
206 BasicBlock &EntryBB = F.getEntryBlock();
207 for (Instruction &I : EntryBB) {
209 Worklist.push_back(SAI);
210 }
211
212 bool Changed = false;
213 for (StructuredAllocaInst *SAI : Worklist)
215 return Changed;
216}
217
227
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:2893
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.