1c62c679cSSebastian Pop //===---- Delinearization.cpp - MultiDimensional Index Delinearization ----===//
2c62c679cSSebastian Pop //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c62c679cSSebastian Pop //
7c62c679cSSebastian Pop //===----------------------------------------------------------------------===//
8c62c679cSSebastian Pop //
9c62c679cSSebastian Pop // This implements an analysis pass that tries to delinearize all GEP
10c62c679cSSebastian Pop // instructions in all loops using the SCEV analysis functionality. This pass is
11c62c679cSSebastian Pop // only used for testing purposes: if your pass needs delinearization, please
12c62c679cSSebastian Pop // use the on-demand SCEVAddRecExpr::delinearize() function.
13c62c679cSSebastian Pop //
14c62c679cSSebastian Pop //===----------------------------------------------------------------------===//
15c62c679cSSebastian Pop 
169db0c572SArthur Eubanks #include "llvm/Analysis/Delinearization.h"
17c62c679cSSebastian Pop #include "llvm/Analysis/LoopInfo.h"
18c62c679cSSebastian Pop #include "llvm/Analysis/Passes.h"
19c62c679cSSebastian Pop #include "llvm/Analysis/ScalarEvolution.h"
20585c594dSPhilip Reames #include "llvm/Analysis/ScalarEvolutionDivision.h"
21c62c679cSSebastian Pop #include "llvm/Analysis/ScalarEvolutionExpressions.h"
22b550cb17SMehdi Amini #include "llvm/IR/Constants.h"
238a8cd2baSChandler Carruth #include "llvm/IR/DerivedTypes.h"
248a8cd2baSChandler Carruth #include "llvm/IR/Function.h"
258394857fSChandler Carruth #include "llvm/IR/InstIterator.h"
268a8cd2baSChandler Carruth #include "llvm/IR/Instructions.h"
279db0c572SArthur Eubanks #include "llvm/IR/PassManager.h"
2805da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
298a8cd2baSChandler Carruth #include "llvm/Pass.h"
30c62c679cSSebastian Pop #include "llvm/Support/Debug.h"
31c62c679cSSebastian Pop #include "llvm/Support/raw_ostream.h"
32c62c679cSSebastian Pop 
33c62c679cSSebastian Pop using namespace llvm;
34c62c679cSSebastian Pop 
35f1221bd0SChandler Carruth #define DL_NAME "delinearize"
36f1221bd0SChandler Carruth #define DEBUG_TYPE DL_NAME
37f1221bd0SChandler Carruth 
38585c594dSPhilip Reames // Return true when S contains at least an undef value.
containsUndefs(const SCEV * S)39585c594dSPhilip Reames static inline bool containsUndefs(const SCEV *S) {
40585c594dSPhilip Reames   return SCEVExprContains(S, [](const SCEV *S) {
41585c594dSPhilip Reames     if (const auto *SU = dyn_cast<SCEVUnknown>(S))
42585c594dSPhilip Reames       return isa<UndefValue>(SU->getValue());
43585c594dSPhilip Reames     return false;
44585c594dSPhilip Reames   });
45585c594dSPhilip Reames }
46585c594dSPhilip Reames 
47585c594dSPhilip Reames namespace {
48585c594dSPhilip Reames 
49585c594dSPhilip Reames // Collect all steps of SCEV expressions.
50585c594dSPhilip Reames struct SCEVCollectStrides {
51585c594dSPhilip Reames   ScalarEvolution &SE;
52585c594dSPhilip Reames   SmallVectorImpl<const SCEV *> &Strides;
53585c594dSPhilip Reames 
SCEVCollectStrides__anona8bc22150211::SCEVCollectStrides54585c594dSPhilip Reames   SCEVCollectStrides(ScalarEvolution &SE, SmallVectorImpl<const SCEV *> &S)
55585c594dSPhilip Reames       : SE(SE), Strides(S) {}
56585c594dSPhilip Reames 
follow__anona8bc22150211::SCEVCollectStrides57585c594dSPhilip Reames   bool follow(const SCEV *S) {
58585c594dSPhilip Reames     if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S))
59585c594dSPhilip Reames       Strides.push_back(AR->getStepRecurrence(SE));
60585c594dSPhilip Reames     return true;
61585c594dSPhilip Reames   }
62585c594dSPhilip Reames 
isDone__anona8bc22150211::SCEVCollectStrides63585c594dSPhilip Reames   bool isDone() const { return false; }
64585c594dSPhilip Reames };
65585c594dSPhilip Reames 
66585c594dSPhilip Reames // Collect all SCEVUnknown and SCEVMulExpr expressions.
67585c594dSPhilip Reames struct SCEVCollectTerms {
68585c594dSPhilip Reames   SmallVectorImpl<const SCEV *> &Terms;
69585c594dSPhilip Reames 
SCEVCollectTerms__anona8bc22150211::SCEVCollectTerms70585c594dSPhilip Reames   SCEVCollectTerms(SmallVectorImpl<const SCEV *> &T) : Terms(T) {}
71585c594dSPhilip Reames 
follow__anona8bc22150211::SCEVCollectTerms72585c594dSPhilip Reames   bool follow(const SCEV *S) {
73585c594dSPhilip Reames     if (isa<SCEVUnknown>(S) || isa<SCEVMulExpr>(S) ||
74585c594dSPhilip Reames         isa<SCEVSignExtendExpr>(S)) {
75585c594dSPhilip Reames       if (!containsUndefs(S))
76585c594dSPhilip Reames         Terms.push_back(S);
77585c594dSPhilip Reames 
78585c594dSPhilip Reames       // Stop recursion: once we collected a term, do not walk its operands.
79585c594dSPhilip Reames       return false;
80585c594dSPhilip Reames     }
81585c594dSPhilip Reames 
82585c594dSPhilip Reames     // Keep looking.
83585c594dSPhilip Reames     return true;
84585c594dSPhilip Reames   }
85585c594dSPhilip Reames 
isDone__anona8bc22150211::SCEVCollectTerms86585c594dSPhilip Reames   bool isDone() const { return false; }
87585c594dSPhilip Reames };
88585c594dSPhilip Reames 
89585c594dSPhilip Reames // Check if a SCEV contains an AddRecExpr.
90585c594dSPhilip Reames struct SCEVHasAddRec {
91585c594dSPhilip Reames   bool &ContainsAddRec;
92585c594dSPhilip Reames 
SCEVHasAddRec__anona8bc22150211::SCEVHasAddRec93585c594dSPhilip Reames   SCEVHasAddRec(bool &ContainsAddRec) : ContainsAddRec(ContainsAddRec) {
94585c594dSPhilip Reames     ContainsAddRec = false;
95585c594dSPhilip Reames   }
96585c594dSPhilip Reames 
follow__anona8bc22150211::SCEVHasAddRec97585c594dSPhilip Reames   bool follow(const SCEV *S) {
98585c594dSPhilip Reames     if (isa<SCEVAddRecExpr>(S)) {
99585c594dSPhilip Reames       ContainsAddRec = true;
100585c594dSPhilip Reames 
101585c594dSPhilip Reames       // Stop recursion: once we collected a term, do not walk its operands.
102585c594dSPhilip Reames       return false;
103585c594dSPhilip Reames     }
104585c594dSPhilip Reames 
105585c594dSPhilip Reames     // Keep looking.
106585c594dSPhilip Reames     return true;
107585c594dSPhilip Reames   }
108585c594dSPhilip Reames 
isDone__anona8bc22150211::SCEVHasAddRec109585c594dSPhilip Reames   bool isDone() const { return false; }
110585c594dSPhilip Reames };
111585c594dSPhilip Reames 
112585c594dSPhilip Reames // Find factors that are multiplied with an expression that (possibly as a
113585c594dSPhilip Reames // subexpression) contains an AddRecExpr. In the expression:
114585c594dSPhilip Reames //
115585c594dSPhilip Reames //  8 * (100 +  %p * %q * (%a + {0, +, 1}_loop))
116585c594dSPhilip Reames //
117585c594dSPhilip Reames // "%p * %q" are factors multiplied by the expression "(%a + {0, +, 1}_loop)"
118585c594dSPhilip Reames // that contains the AddRec {0, +, 1}_loop. %p * %q are likely to be array size
119585c594dSPhilip Reames // parameters as they form a product with an induction variable.
120585c594dSPhilip Reames //
121585c594dSPhilip Reames // This collector expects all array size parameters to be in the same MulExpr.
122585c594dSPhilip Reames // It might be necessary to later add support for collecting parameters that are
123585c594dSPhilip Reames // spread over different nested MulExpr.
124585c594dSPhilip Reames struct SCEVCollectAddRecMultiplies {
125585c594dSPhilip Reames   SmallVectorImpl<const SCEV *> &Terms;
126585c594dSPhilip Reames   ScalarEvolution &SE;
127585c594dSPhilip Reames 
SCEVCollectAddRecMultiplies__anona8bc22150211::SCEVCollectAddRecMultiplies128585c594dSPhilip Reames   SCEVCollectAddRecMultiplies(SmallVectorImpl<const SCEV *> &T,
129585c594dSPhilip Reames                               ScalarEvolution &SE)
130585c594dSPhilip Reames       : Terms(T), SE(SE) {}
131585c594dSPhilip Reames 
follow__anona8bc22150211::SCEVCollectAddRecMultiplies132585c594dSPhilip Reames   bool follow(const SCEV *S) {
133585c594dSPhilip Reames     if (auto *Mul = dyn_cast<SCEVMulExpr>(S)) {
134585c594dSPhilip Reames       bool HasAddRec = false;
135585c594dSPhilip Reames       SmallVector<const SCEV *, 0> Operands;
136*601b3a13SKazu Hirata       for (const auto *Op : Mul->operands()) {
137585c594dSPhilip Reames         const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(Op);
138585c594dSPhilip Reames         if (Unknown && !isa<CallInst>(Unknown->getValue())) {
139585c594dSPhilip Reames           Operands.push_back(Op);
140585c594dSPhilip Reames         } else if (Unknown) {
141585c594dSPhilip Reames           HasAddRec = true;
142585c594dSPhilip Reames         } else {
143585c594dSPhilip Reames           bool ContainsAddRec = false;
144585c594dSPhilip Reames           SCEVHasAddRec ContiansAddRec(ContainsAddRec);
145585c594dSPhilip Reames           visitAll(Op, ContiansAddRec);
146585c594dSPhilip Reames           HasAddRec |= ContainsAddRec;
147585c594dSPhilip Reames         }
148585c594dSPhilip Reames       }
149585c594dSPhilip Reames       if (Operands.size() == 0)
150585c594dSPhilip Reames         return true;
151585c594dSPhilip Reames 
152585c594dSPhilip Reames       if (!HasAddRec)
153585c594dSPhilip Reames         return false;
154585c594dSPhilip Reames 
155585c594dSPhilip Reames       Terms.push_back(SE.getMulExpr(Operands));
156585c594dSPhilip Reames       // Stop recursion: once we collected a term, do not walk its operands.
157585c594dSPhilip Reames       return false;
158585c594dSPhilip Reames     }
159585c594dSPhilip Reames 
160585c594dSPhilip Reames     // Keep looking.
161585c594dSPhilip Reames     return true;
162585c594dSPhilip Reames   }
163585c594dSPhilip Reames 
isDone__anona8bc22150211::SCEVCollectAddRecMultiplies164585c594dSPhilip Reames   bool isDone() const { return false; }
165585c594dSPhilip Reames };
166585c594dSPhilip Reames 
167585c594dSPhilip Reames } // end anonymous namespace
168585c594dSPhilip Reames 
169585c594dSPhilip Reames /// Find parametric terms in this SCEVAddRecExpr. We first for parameters in
170585c594dSPhilip Reames /// two places:
171585c594dSPhilip Reames ///   1) The strides of AddRec expressions.
172585c594dSPhilip Reames ///   2) Unknowns that are multiplied with AddRec expressions.
collectParametricTerms(ScalarEvolution & SE,const SCEV * Expr,SmallVectorImpl<const SCEV * > & Terms)173585c594dSPhilip Reames void llvm::collectParametricTerms(ScalarEvolution &SE, const SCEV *Expr,
174585c594dSPhilip Reames                                   SmallVectorImpl<const SCEV *> &Terms) {
175585c594dSPhilip Reames   SmallVector<const SCEV *, 4> Strides;
176585c594dSPhilip Reames   SCEVCollectStrides StrideCollector(SE, Strides);
177585c594dSPhilip Reames   visitAll(Expr, StrideCollector);
178585c594dSPhilip Reames 
179585c594dSPhilip Reames   LLVM_DEBUG({
180585c594dSPhilip Reames     dbgs() << "Strides:\n";
181585c594dSPhilip Reames     for (const SCEV *S : Strides)
182585c594dSPhilip Reames       dbgs() << *S << "\n";
183585c594dSPhilip Reames   });
184585c594dSPhilip Reames 
185585c594dSPhilip Reames   for (const SCEV *S : Strides) {
186585c594dSPhilip Reames     SCEVCollectTerms TermCollector(Terms);
187585c594dSPhilip Reames     visitAll(S, TermCollector);
188585c594dSPhilip Reames   }
189585c594dSPhilip Reames 
190585c594dSPhilip Reames   LLVM_DEBUG({
191585c594dSPhilip Reames     dbgs() << "Terms:\n";
192585c594dSPhilip Reames     for (const SCEV *T : Terms)
193585c594dSPhilip Reames       dbgs() << *T << "\n";
194585c594dSPhilip Reames   });
195585c594dSPhilip Reames 
196585c594dSPhilip Reames   SCEVCollectAddRecMultiplies MulCollector(Terms, SE);
197585c594dSPhilip Reames   visitAll(Expr, MulCollector);
198585c594dSPhilip Reames }
199585c594dSPhilip Reames 
findArrayDimensionsRec(ScalarEvolution & SE,SmallVectorImpl<const SCEV * > & Terms,SmallVectorImpl<const SCEV * > & Sizes)200585c594dSPhilip Reames static bool findArrayDimensionsRec(ScalarEvolution &SE,
201585c594dSPhilip Reames                                    SmallVectorImpl<const SCEV *> &Terms,
202585c594dSPhilip Reames                                    SmallVectorImpl<const SCEV *> &Sizes) {
203585c594dSPhilip Reames   int Last = Terms.size() - 1;
204585c594dSPhilip Reames   const SCEV *Step = Terms[Last];
205585c594dSPhilip Reames 
206585c594dSPhilip Reames   // End of recursion.
207585c594dSPhilip Reames   if (Last == 0) {
208585c594dSPhilip Reames     if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Step)) {
209585c594dSPhilip Reames       SmallVector<const SCEV *, 2> Qs;
210585c594dSPhilip Reames       for (const SCEV *Op : M->operands())
211585c594dSPhilip Reames         if (!isa<SCEVConstant>(Op))
212585c594dSPhilip Reames           Qs.push_back(Op);
213585c594dSPhilip Reames 
214585c594dSPhilip Reames       Step = SE.getMulExpr(Qs);
215585c594dSPhilip Reames     }
216585c594dSPhilip Reames 
217585c594dSPhilip Reames     Sizes.push_back(Step);
218585c594dSPhilip Reames     return true;
219585c594dSPhilip Reames   }
220585c594dSPhilip Reames 
221585c594dSPhilip Reames   for (const SCEV *&Term : Terms) {
222585c594dSPhilip Reames     // Normalize the terms before the next call to findArrayDimensionsRec.
223585c594dSPhilip Reames     const SCEV *Q, *R;
224585c594dSPhilip Reames     SCEVDivision::divide(SE, Term, Step, &Q, &R);
225585c594dSPhilip Reames 
226585c594dSPhilip Reames     // Bail out when GCD does not evenly divide one of the terms.
227585c594dSPhilip Reames     if (!R->isZero())
228585c594dSPhilip Reames       return false;
229585c594dSPhilip Reames 
230585c594dSPhilip Reames     Term = Q;
231585c594dSPhilip Reames   }
232585c594dSPhilip Reames 
233585c594dSPhilip Reames   // Remove all SCEVConstants.
234585c594dSPhilip Reames   erase_if(Terms, [](const SCEV *E) { return isa<SCEVConstant>(E); });
235585c594dSPhilip Reames 
236585c594dSPhilip Reames   if (Terms.size() > 0)
237585c594dSPhilip Reames     if (!findArrayDimensionsRec(SE, Terms, Sizes))
238585c594dSPhilip Reames       return false;
239585c594dSPhilip Reames 
240585c594dSPhilip Reames   Sizes.push_back(Step);
241585c594dSPhilip Reames   return true;
242585c594dSPhilip Reames }
243585c594dSPhilip Reames 
244585c594dSPhilip Reames // Returns true when one of the SCEVs of Terms contains a SCEVUnknown parameter.
containsParameters(SmallVectorImpl<const SCEV * > & Terms)245585c594dSPhilip Reames static inline bool containsParameters(SmallVectorImpl<const SCEV *> &Terms) {
246585c594dSPhilip Reames   for (const SCEV *T : Terms)
247585c594dSPhilip Reames     if (SCEVExprContains(T, [](const SCEV *S) { return isa<SCEVUnknown>(S); }))
248585c594dSPhilip Reames       return true;
249585c594dSPhilip Reames 
250585c594dSPhilip Reames   return false;
251585c594dSPhilip Reames }
252585c594dSPhilip Reames 
253585c594dSPhilip Reames // Return the number of product terms in S.
numberOfTerms(const SCEV * S)254585c594dSPhilip Reames static inline int numberOfTerms(const SCEV *S) {
255585c594dSPhilip Reames   if (const SCEVMulExpr *Expr = dyn_cast<SCEVMulExpr>(S))
256585c594dSPhilip Reames     return Expr->getNumOperands();
257585c594dSPhilip Reames   return 1;
258585c594dSPhilip Reames }
259585c594dSPhilip Reames 
removeConstantFactors(ScalarEvolution & SE,const SCEV * T)260585c594dSPhilip Reames static const SCEV *removeConstantFactors(ScalarEvolution &SE, const SCEV *T) {
261585c594dSPhilip Reames   if (isa<SCEVConstant>(T))
262585c594dSPhilip Reames     return nullptr;
263585c594dSPhilip Reames 
264585c594dSPhilip Reames   if (isa<SCEVUnknown>(T))
265585c594dSPhilip Reames     return T;
266585c594dSPhilip Reames 
267585c594dSPhilip Reames   if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(T)) {
268585c594dSPhilip Reames     SmallVector<const SCEV *, 2> Factors;
269585c594dSPhilip Reames     for (const SCEV *Op : M->operands())
270585c594dSPhilip Reames       if (!isa<SCEVConstant>(Op))
271585c594dSPhilip Reames         Factors.push_back(Op);
272585c594dSPhilip Reames 
273585c594dSPhilip Reames     return SE.getMulExpr(Factors);
274585c594dSPhilip Reames   }
275585c594dSPhilip Reames 
276585c594dSPhilip Reames   return T;
277585c594dSPhilip Reames }
278585c594dSPhilip Reames 
findArrayDimensions(ScalarEvolution & SE,SmallVectorImpl<const SCEV * > & Terms,SmallVectorImpl<const SCEV * > & Sizes,const SCEV * ElementSize)279585c594dSPhilip Reames void llvm::findArrayDimensions(ScalarEvolution &SE,
280585c594dSPhilip Reames                                SmallVectorImpl<const SCEV *> &Terms,
281585c594dSPhilip Reames                                SmallVectorImpl<const SCEV *> &Sizes,
282585c594dSPhilip Reames                                const SCEV *ElementSize) {
283585c594dSPhilip Reames   if (Terms.size() < 1 || !ElementSize)
284585c594dSPhilip Reames     return;
285585c594dSPhilip Reames 
286585c594dSPhilip Reames   // Early return when Terms do not contain parameters: we do not delinearize
287585c594dSPhilip Reames   // non parametric SCEVs.
288585c594dSPhilip Reames   if (!containsParameters(Terms))
289585c594dSPhilip Reames     return;
290585c594dSPhilip Reames 
291585c594dSPhilip Reames   LLVM_DEBUG({
292585c594dSPhilip Reames     dbgs() << "Terms:\n";
293585c594dSPhilip Reames     for (const SCEV *T : Terms)
294585c594dSPhilip Reames       dbgs() << *T << "\n";
295585c594dSPhilip Reames   });
296585c594dSPhilip Reames 
297585c594dSPhilip Reames   // Remove duplicates.
298585c594dSPhilip Reames   array_pod_sort(Terms.begin(), Terms.end());
299585c594dSPhilip Reames   Terms.erase(std::unique(Terms.begin(), Terms.end()), Terms.end());
300585c594dSPhilip Reames 
301585c594dSPhilip Reames   // Put larger terms first.
302585c594dSPhilip Reames   llvm::sort(Terms, [](const SCEV *LHS, const SCEV *RHS) {
303585c594dSPhilip Reames     return numberOfTerms(LHS) > numberOfTerms(RHS);
304585c594dSPhilip Reames   });
305585c594dSPhilip Reames 
306585c594dSPhilip Reames   // Try to divide all terms by the element size. If term is not divisible by
307585c594dSPhilip Reames   // element size, proceed with the original term.
308585c594dSPhilip Reames   for (const SCEV *&Term : Terms) {
309585c594dSPhilip Reames     const SCEV *Q, *R;
310585c594dSPhilip Reames     SCEVDivision::divide(SE, Term, ElementSize, &Q, &R);
311585c594dSPhilip Reames     if (!Q->isZero())
312585c594dSPhilip Reames       Term = Q;
313585c594dSPhilip Reames   }
314585c594dSPhilip Reames 
315585c594dSPhilip Reames   SmallVector<const SCEV *, 4> NewTerms;
316585c594dSPhilip Reames 
317585c594dSPhilip Reames   // Remove constant factors.
318585c594dSPhilip Reames   for (const SCEV *T : Terms)
319585c594dSPhilip Reames     if (const SCEV *NewT = removeConstantFactors(SE, T))
320585c594dSPhilip Reames       NewTerms.push_back(NewT);
321585c594dSPhilip Reames 
322585c594dSPhilip Reames   LLVM_DEBUG({
323585c594dSPhilip Reames     dbgs() << "Terms after sorting:\n";
324585c594dSPhilip Reames     for (const SCEV *T : NewTerms)
325585c594dSPhilip Reames       dbgs() << *T << "\n";
326585c594dSPhilip Reames   });
327585c594dSPhilip Reames 
328585c594dSPhilip Reames   if (NewTerms.empty() || !findArrayDimensionsRec(SE, NewTerms, Sizes)) {
329585c594dSPhilip Reames     Sizes.clear();
330585c594dSPhilip Reames     return;
331585c594dSPhilip Reames   }
332585c594dSPhilip Reames 
333585c594dSPhilip Reames   // The last element to be pushed into Sizes is the size of an element.
334585c594dSPhilip Reames   Sizes.push_back(ElementSize);
335585c594dSPhilip Reames 
336585c594dSPhilip Reames   LLVM_DEBUG({
337585c594dSPhilip Reames     dbgs() << "Sizes:\n";
338585c594dSPhilip Reames     for (const SCEV *S : Sizes)
339585c594dSPhilip Reames       dbgs() << *S << "\n";
340585c594dSPhilip Reames   });
341585c594dSPhilip Reames }
342585c594dSPhilip Reames 
computeAccessFunctions(ScalarEvolution & SE,const SCEV * Expr,SmallVectorImpl<const SCEV * > & Subscripts,SmallVectorImpl<const SCEV * > & Sizes)343585c594dSPhilip Reames void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
344585c594dSPhilip Reames                                   SmallVectorImpl<const SCEV *> &Subscripts,
345585c594dSPhilip Reames                                   SmallVectorImpl<const SCEV *> &Sizes) {
346585c594dSPhilip Reames   // Early exit in case this SCEV is not an affine multivariate function.
347585c594dSPhilip Reames   if (Sizes.empty())
348585c594dSPhilip Reames     return;
349585c594dSPhilip Reames 
350585c594dSPhilip Reames   if (auto *AR = dyn_cast<SCEVAddRecExpr>(Expr))
351585c594dSPhilip Reames     if (!AR->isAffine())
352585c594dSPhilip Reames       return;
353585c594dSPhilip Reames 
354585c594dSPhilip Reames   const SCEV *Res = Expr;
355585c594dSPhilip Reames   int Last = Sizes.size() - 1;
356585c594dSPhilip Reames   for (int i = Last; i >= 0; i--) {
357585c594dSPhilip Reames     const SCEV *Q, *R;
358585c594dSPhilip Reames     SCEVDivision::divide(SE, Res, Sizes[i], &Q, &R);
359585c594dSPhilip Reames 
360585c594dSPhilip Reames     LLVM_DEBUG({
361585c594dSPhilip Reames       dbgs() << "Res: " << *Res << "\n";
362585c594dSPhilip Reames       dbgs() << "Sizes[i]: " << *Sizes[i] << "\n";
363585c594dSPhilip Reames       dbgs() << "Res divided by Sizes[i]:\n";
364585c594dSPhilip Reames       dbgs() << "Quotient: " << *Q << "\n";
365585c594dSPhilip Reames       dbgs() << "Remainder: " << *R << "\n";
366585c594dSPhilip Reames     });
367585c594dSPhilip Reames 
368585c594dSPhilip Reames     Res = Q;
369585c594dSPhilip Reames 
370585c594dSPhilip Reames     // Do not record the last subscript corresponding to the size of elements in
371585c594dSPhilip Reames     // the array.
372585c594dSPhilip Reames     if (i == Last) {
373585c594dSPhilip Reames 
374088577a3SMichael Kruse       // Bail out if the byte offset is non-zero.
375088577a3SMichael Kruse       if (!R->isZero()) {
376585c594dSPhilip Reames         Subscripts.clear();
377585c594dSPhilip Reames         Sizes.clear();
378585c594dSPhilip Reames         return;
379585c594dSPhilip Reames       }
380585c594dSPhilip Reames 
381585c594dSPhilip Reames       continue;
382585c594dSPhilip Reames     }
383585c594dSPhilip Reames 
384585c594dSPhilip Reames     // Record the access function for the current subscript.
385585c594dSPhilip Reames     Subscripts.push_back(R);
386585c594dSPhilip Reames   }
387585c594dSPhilip Reames 
388585c594dSPhilip Reames   // Also push in last position the remainder of the last division: it will be
389585c594dSPhilip Reames   // the access function of the innermost dimension.
390585c594dSPhilip Reames   Subscripts.push_back(Res);
391585c594dSPhilip Reames 
392585c594dSPhilip Reames   std::reverse(Subscripts.begin(), Subscripts.end());
393585c594dSPhilip Reames 
394585c594dSPhilip Reames   LLVM_DEBUG({
395585c594dSPhilip Reames     dbgs() << "Subscripts:\n";
396585c594dSPhilip Reames     for (const SCEV *S : Subscripts)
397585c594dSPhilip Reames       dbgs() << *S << "\n";
398585c594dSPhilip Reames   });
399585c594dSPhilip Reames }
400585c594dSPhilip Reames 
401585c594dSPhilip Reames /// Splits the SCEV into two vectors of SCEVs representing the subscripts and
402585c594dSPhilip Reames /// sizes of an array access. Returns the remainder of the delinearization that
403585c594dSPhilip Reames /// is the offset start of the array.  The SCEV->delinearize algorithm computes
404585c594dSPhilip Reames /// the multiples of SCEV coefficients: that is a pattern matching of sub
405585c594dSPhilip Reames /// expressions in the stride and base of a SCEV corresponding to the
406585c594dSPhilip Reames /// computation of a GCD (greatest common divisor) of base and stride.  When
407585c594dSPhilip Reames /// SCEV->delinearize fails, it returns the SCEV unchanged.
408585c594dSPhilip Reames ///
409585c594dSPhilip Reames /// For example: when analyzing the memory access A[i][j][k] in this loop nest
410585c594dSPhilip Reames ///
411585c594dSPhilip Reames ///  void foo(long n, long m, long o, double A[n][m][o]) {
412585c594dSPhilip Reames ///
413585c594dSPhilip Reames ///    for (long i = 0; i < n; i++)
414585c594dSPhilip Reames ///      for (long j = 0; j < m; j++)
415585c594dSPhilip Reames ///        for (long k = 0; k < o; k++)
416585c594dSPhilip Reames ///          A[i][j][k] = 1.0;
417585c594dSPhilip Reames ///  }
418585c594dSPhilip Reames ///
419585c594dSPhilip Reames /// the delinearization input is the following AddRec SCEV:
420585c594dSPhilip Reames ///
421585c594dSPhilip Reames ///  AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
422585c594dSPhilip Reames ///
423585c594dSPhilip Reames /// From this SCEV, we are able to say that the base offset of the access is %A
424585c594dSPhilip Reames /// because it appears as an offset that does not divide any of the strides in
425585c594dSPhilip Reames /// the loops:
426585c594dSPhilip Reames ///
427585c594dSPhilip Reames ///  CHECK: Base offset: %A
428585c594dSPhilip Reames ///
429585c594dSPhilip Reames /// and then SCEV->delinearize determines the size of some of the dimensions of
430585c594dSPhilip Reames /// the array as these are the multiples by which the strides are happening:
431585c594dSPhilip Reames ///
432585c594dSPhilip Reames ///  CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double)
433585c594dSPhilip Reames ///  bytes.
434585c594dSPhilip Reames ///
435585c594dSPhilip Reames /// Note that the outermost dimension remains of UnknownSize because there are
436585c594dSPhilip Reames /// no strides that would help identifying the size of the last dimension: when
437585c594dSPhilip Reames /// the array has been statically allocated, one could compute the size of that
438585c594dSPhilip Reames /// dimension by dividing the overall size of the array by the size of the known
439585c594dSPhilip Reames /// dimensions: %m * %o * 8.
440585c594dSPhilip Reames ///
441585c594dSPhilip Reames /// Finally delinearize provides the access functions for the array reference
442585c594dSPhilip Reames /// that does correspond to A[i][j][k] of the above C testcase:
443585c594dSPhilip Reames ///
444585c594dSPhilip Reames ///  CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
445585c594dSPhilip Reames ///
446585c594dSPhilip Reames /// The testcases are checking the output of a function pass:
447585c594dSPhilip Reames /// DelinearizationPass that walks through all loads and stores of a function
448585c594dSPhilip Reames /// asking for the SCEV of the memory access with respect to all enclosing
449585c594dSPhilip Reames /// loops, calling SCEV->delinearize on that and printing the results.
delinearize(ScalarEvolution & SE,const SCEV * Expr,SmallVectorImpl<const SCEV * > & Subscripts,SmallVectorImpl<const SCEV * > & Sizes,const SCEV * ElementSize)450585c594dSPhilip Reames void llvm::delinearize(ScalarEvolution &SE, const SCEV *Expr,
451585c594dSPhilip Reames                        SmallVectorImpl<const SCEV *> &Subscripts,
452585c594dSPhilip Reames                        SmallVectorImpl<const SCEV *> &Sizes,
453585c594dSPhilip Reames                        const SCEV *ElementSize) {
454585c594dSPhilip Reames   // First step: collect parametric terms.
455585c594dSPhilip Reames   SmallVector<const SCEV *, 4> Terms;
456585c594dSPhilip Reames   collectParametricTerms(SE, Expr, Terms);
457585c594dSPhilip Reames 
458585c594dSPhilip Reames   if (Terms.empty())
459585c594dSPhilip Reames     return;
460585c594dSPhilip Reames 
461585c594dSPhilip Reames   // Second step: find subscript sizes.
462585c594dSPhilip Reames   findArrayDimensions(SE, Terms, Sizes, ElementSize);
463585c594dSPhilip Reames 
464585c594dSPhilip Reames   if (Sizes.empty())
465585c594dSPhilip Reames     return;
466585c594dSPhilip Reames 
467585c594dSPhilip Reames   // Third step: compute the access functions for each subscript.
468585c594dSPhilip Reames   computeAccessFunctions(SE, Expr, Subscripts, Sizes);
469585c594dSPhilip Reames 
470585c594dSPhilip Reames   if (Subscripts.empty())
471585c594dSPhilip Reames     return;
472585c594dSPhilip Reames 
473585c594dSPhilip Reames   LLVM_DEBUG({
474585c594dSPhilip Reames     dbgs() << "succeeded to delinearize " << *Expr << "\n";
475585c594dSPhilip Reames     dbgs() << "ArrayDecl[UnknownSize]";
476585c594dSPhilip Reames     for (const SCEV *S : Sizes)
477585c594dSPhilip Reames       dbgs() << "[" << *S << "]";
478585c594dSPhilip Reames 
479585c594dSPhilip Reames     dbgs() << "\nArrayRef";
480585c594dSPhilip Reames     for (const SCEV *S : Subscripts)
481585c594dSPhilip Reames       dbgs() << "[" << *S << "]";
482585c594dSPhilip Reames     dbgs() << "\n";
483585c594dSPhilip Reames   });
484585c594dSPhilip Reames }
485585c594dSPhilip Reames 
getIndexExpressionsFromGEP(ScalarEvolution & SE,const GetElementPtrInst * GEP,SmallVectorImpl<const SCEV * > & Subscripts,SmallVectorImpl<int> & Sizes)486e741fabcSPhilip Reames bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
487e741fabcSPhilip Reames                                       const GetElementPtrInst *GEP,
488e741fabcSPhilip Reames                                       SmallVectorImpl<const SCEV *> &Subscripts,
489e741fabcSPhilip Reames                                       SmallVectorImpl<int> &Sizes) {
490e741fabcSPhilip Reames   assert(Subscripts.empty() && Sizes.empty() &&
491e741fabcSPhilip Reames          "Expected output lists to be empty on entry to this function.");
492e741fabcSPhilip Reames   assert(GEP && "getIndexExpressionsFromGEP called with a null GEP");
493e741fabcSPhilip Reames   Type *Ty = nullptr;
494e741fabcSPhilip Reames   bool DroppedFirstDim = false;
495e741fabcSPhilip Reames   for (unsigned i = 1; i < GEP->getNumOperands(); i++) {
496e741fabcSPhilip Reames     const SCEV *Expr = SE.getSCEV(GEP->getOperand(i));
497e741fabcSPhilip Reames     if (i == 1) {
498e741fabcSPhilip Reames       Ty = GEP->getSourceElementType();
499e741fabcSPhilip Reames       if (auto *Const = dyn_cast<SCEVConstant>(Expr))
500e741fabcSPhilip Reames         if (Const->getValue()->isZero()) {
501e741fabcSPhilip Reames           DroppedFirstDim = true;
502e741fabcSPhilip Reames           continue;
503e741fabcSPhilip Reames         }
504e741fabcSPhilip Reames       Subscripts.push_back(Expr);
505e741fabcSPhilip Reames       continue;
506e741fabcSPhilip Reames     }
507e741fabcSPhilip Reames 
508e741fabcSPhilip Reames     auto *ArrayTy = dyn_cast<ArrayType>(Ty);
509e741fabcSPhilip Reames     if (!ArrayTy) {
510e741fabcSPhilip Reames       Subscripts.clear();
511e741fabcSPhilip Reames       Sizes.clear();
512e741fabcSPhilip Reames       return false;
513e741fabcSPhilip Reames     }
514e741fabcSPhilip Reames 
515e741fabcSPhilip Reames     Subscripts.push_back(Expr);
516e741fabcSPhilip Reames     if (!(DroppedFirstDim && i == 2))
517e741fabcSPhilip Reames       Sizes.push_back(ArrayTy->getNumElements());
518e741fabcSPhilip Reames 
519e741fabcSPhilip Reames     Ty = ArrayTy->getElementType();
520e741fabcSPhilip Reames   }
521e741fabcSPhilip Reames   return !Subscripts.empty();
522e741fabcSPhilip Reames }
523e741fabcSPhilip Reames 
tryDelinearizeFixedSizeImpl(ScalarEvolution * SE,Instruction * Inst,const SCEV * AccessFn,SmallVectorImpl<const SCEV * > & Subscripts,SmallVectorImpl<int> & Sizes)5244c77d027SCongzhe Cao bool llvm::tryDelinearizeFixedSizeImpl(
5254c77d027SCongzhe Cao     ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn,
5264c77d027SCongzhe Cao     SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<int> &Sizes) {
5274c77d027SCongzhe Cao   Value *SrcPtr = getLoadStorePointerOperand(Inst);
5284c77d027SCongzhe Cao 
5294c77d027SCongzhe Cao   // Check the simple case where the array dimensions are fixed size.
5304c77d027SCongzhe Cao   auto *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr);
5314c77d027SCongzhe Cao   if (!SrcGEP)
5324c77d027SCongzhe Cao     return false;
5334c77d027SCongzhe Cao 
5344c77d027SCongzhe Cao   getIndexExpressionsFromGEP(*SE, SrcGEP, Subscripts, Sizes);
5354c77d027SCongzhe Cao 
5364c77d027SCongzhe Cao   // Check that the two size arrays are non-empty and equal in length and
5374c77d027SCongzhe Cao   // value.
5384c77d027SCongzhe Cao   // TODO: it would be better to let the caller to clear Subscripts, similar
5394c77d027SCongzhe Cao   // to how we handle Sizes.
5404c77d027SCongzhe Cao   if (Sizes.empty() || Subscripts.size() <= 1) {
5414c77d027SCongzhe Cao     Subscripts.clear();
5424c77d027SCongzhe Cao     return false;
5434c77d027SCongzhe Cao   }
5444c77d027SCongzhe Cao 
5454c77d027SCongzhe Cao   // Check that for identical base pointers we do not miss index offsets
5464c77d027SCongzhe Cao   // that have been added before this GEP is applied.
5474c77d027SCongzhe Cao   Value *SrcBasePtr = SrcGEP->getOperand(0)->stripPointerCasts();
5484c77d027SCongzhe Cao   const SCEVUnknown *SrcBase =
5494c77d027SCongzhe Cao       dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFn));
5504c77d027SCongzhe Cao   if (!SrcBase || SrcBasePtr != SrcBase->getValue()) {
5514c77d027SCongzhe Cao     Subscripts.clear();
5524c77d027SCongzhe Cao     return false;
5534c77d027SCongzhe Cao   }
5544c77d027SCongzhe Cao 
5554c77d027SCongzhe Cao   assert(Subscripts.size() == Sizes.size() + 1 &&
5564c77d027SCongzhe Cao          "Expected equal number of entries in the list of size and "
5574c77d027SCongzhe Cao          "subscript.");
5584c77d027SCongzhe Cao 
5594c77d027SCongzhe Cao   return true;
5604c77d027SCongzhe Cao }
5614c77d027SCongzhe Cao 
5629e501ec2SBenjamin Kramer namespace {
5639e501ec2SBenjamin Kramer 
564c62c679cSSebastian Pop class Delinearization : public FunctionPass {
565c62c679cSSebastian Pop   Delinearization(const Delinearization &); // do not implement
566c62c679cSSebastian Pop protected:
567c62c679cSSebastian Pop   Function *F;
568c62c679cSSebastian Pop   LoopInfo *LI;
569c62c679cSSebastian Pop   ScalarEvolution *SE;
570c62c679cSSebastian Pop 
571c62c679cSSebastian Pop public:
572c62c679cSSebastian Pop   static char ID; // Pass identification, replacement for typeid
573c62c679cSSebastian Pop 
Delinearization()574c62c679cSSebastian Pop   Delinearization() : FunctionPass(ID) {
575c62c679cSSebastian Pop     initializeDelinearizationPass(*PassRegistry::getPassRegistry());
576c62c679cSSebastian Pop   }
577e9ba759cSCraig Topper   bool runOnFunction(Function &F) override;
578e9ba759cSCraig Topper   void getAnalysisUsage(AnalysisUsage &AU) const override;
5799f008867SCraig Topper   void print(raw_ostream &O, const Module *M = nullptr) const override;
580c62c679cSSebastian Pop };
581c62c679cSSebastian Pop 
printDelinearization(raw_ostream & O,Function * F,LoopInfo * LI,ScalarEvolution * SE)5829db0c572SArthur Eubanks void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
5839db0c572SArthur Eubanks                           ScalarEvolution *SE) {
584c62c679cSSebastian Pop   O << "Delinearization on function " << F->getName() << ":\n";
58528d31320SKazu Hirata   for (Instruction &Inst : instructions(F)) {
5867ee14724SSebastian Pop     // Only analyze loads and stores.
58728d31320SKazu Hirata     if (!isa<StoreInst>(&Inst) && !isa<LoadInst>(&Inst) &&
58828d31320SKazu Hirata         !isa<GetElementPtrInst>(&Inst))
589c62c679cSSebastian Pop       continue;
590c62c679cSSebastian Pop 
59128d31320SKazu Hirata     const BasicBlock *BB = Inst.getParent();
592c62c679cSSebastian Pop     // Delinearize the memory access as analyzed in all the surrounding loops.
593c62c679cSSebastian Pop     // Do not analyze memory accesses outside loops.
5949f008867SCraig Topper     for (Loop *L = LI->getLoopFor(BB); L != nullptr; L = L->getParentLoop()) {
59528d31320SKazu Hirata       const SCEV *AccessFn = SE->getSCEVAtScope(getPointerOperand(&Inst), L);
59628e6b97bSSebastian Pop 
59728e6b97bSSebastian Pop       const SCEVUnknown *BasePointer =
59828e6b97bSSebastian Pop           dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFn));
59928e6b97bSSebastian Pop       // Do not delinearize if we cannot find the base pointer.
60028e6b97bSSebastian Pop       if (!BasePointer)
60128e6b97bSSebastian Pop         break;
60228e6b97bSSebastian Pop       AccessFn = SE->getMinusSCEV(AccessFn, BasePointer);
60328e6b97bSSebastian Pop 
604c3d9db23STobias Grosser       O << "\n";
60528d31320SKazu Hirata       O << "Inst:" << Inst << "\n";
606c3d9db23STobias Grosser       O << "In Loop with Header: " << L->getHeader()->getName() << "\n";
607374bce0cSTobias Grosser       O << "AccessFunction: " << *AccessFn << "\n";
608c62c679cSSebastian Pop 
609c62c679cSSebastian Pop       SmallVector<const SCEV *, 3> Subscripts, Sizes;
610585c594dSPhilip Reames       delinearize(*SE, AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst));
611a6e58605SSebastian Pop       if (Subscripts.size() == 0 || Sizes.size() == 0 ||
612448712b1SSebastian Pop           Subscripts.size() != Sizes.size()) {
613c62c679cSSebastian Pop         O << "failed to delinearize\n";
614c62c679cSSebastian Pop         continue;
615c62c679cSSebastian Pop       }
61628e6b97bSSebastian Pop 
61728e6b97bSSebastian Pop       O << "Base offset: " << *BasePointer << "\n";
618c62c679cSSebastian Pop       O << "ArrayDecl[UnknownSize]";
619448712b1SSebastian Pop       int Size = Subscripts.size();
620c62c679cSSebastian Pop       for (int i = 0; i < Size - 1; i++)
621c62c679cSSebastian Pop         O << "[" << *Sizes[i] << "]";
622c62c679cSSebastian Pop       O << " with elements of " << *Sizes[Size - 1] << " bytes.\n";
623c62c679cSSebastian Pop 
624c62c679cSSebastian Pop       O << "ArrayRef";
625c62c679cSSebastian Pop       for (int i = 0; i < Size; i++)
626c62c679cSSebastian Pop         O << "[" << *Subscripts[i] << "]";
627c62c679cSSebastian Pop       O << "\n";
628c62c679cSSebastian Pop     }
629c62c679cSSebastian Pop   }
630c62c679cSSebastian Pop }
631c62c679cSSebastian Pop 
6329db0c572SArthur Eubanks } // end anonymous namespace
6339db0c572SArthur Eubanks 
getAnalysisUsage(AnalysisUsage & AU) const6349db0c572SArthur Eubanks void Delinearization::getAnalysisUsage(AnalysisUsage &AU) const {
6359db0c572SArthur Eubanks   AU.setPreservesAll();
6369db0c572SArthur Eubanks   AU.addRequired<LoopInfoWrapperPass>();
6379db0c572SArthur Eubanks   AU.addRequired<ScalarEvolutionWrapperPass>();
6389db0c572SArthur Eubanks }
6399db0c572SArthur Eubanks 
runOnFunction(Function & F)6409db0c572SArthur Eubanks bool Delinearization::runOnFunction(Function &F) {
6419db0c572SArthur Eubanks   this->F = &F;
6429db0c572SArthur Eubanks   SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
6439db0c572SArthur Eubanks   LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
6449db0c572SArthur Eubanks   return false;
6459db0c572SArthur Eubanks }
6469db0c572SArthur Eubanks 
print(raw_ostream & O,const Module *) const6479db0c572SArthur Eubanks void Delinearization::print(raw_ostream &O, const Module *) const {
6489db0c572SArthur Eubanks   printDelinearization(O, F, LI, SE);
6499db0c572SArthur Eubanks }
6509db0c572SArthur Eubanks 
651c62c679cSSebastian Pop char Delinearization::ID = 0;
652c62c679cSSebastian Pop static const char delinearization_name[] = "Delinearization";
INITIALIZE_PASS_BEGIN(Delinearization,DL_NAME,delinearization_name,true,true)653c62c679cSSebastian Pop INITIALIZE_PASS_BEGIN(Delinearization, DL_NAME, delinearization_name, true,
654c62c679cSSebastian Pop                       true)
6554f8f307cSChandler Carruth INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
656c62c679cSSebastian Pop INITIALIZE_PASS_END(Delinearization, DL_NAME, delinearization_name, true, true)
657c62c679cSSebastian Pop 
658c62c679cSSebastian Pop FunctionPass *llvm::createDelinearizationPass() { return new Delinearization; }
6599db0c572SArthur Eubanks 
DelinearizationPrinterPass(raw_ostream & OS)6609db0c572SArthur Eubanks DelinearizationPrinterPass::DelinearizationPrinterPass(raw_ostream &OS)
6619db0c572SArthur Eubanks     : OS(OS) {}
run(Function & F,FunctionAnalysisManager & AM)6629db0c572SArthur Eubanks PreservedAnalyses DelinearizationPrinterPass::run(Function &F,
6639db0c572SArthur Eubanks                                                   FunctionAnalysisManager &AM) {
6649db0c572SArthur Eubanks   printDelinearization(OS, &F, &AM.getResult<LoopAnalysis>(F),
6659db0c572SArthur Eubanks                        &AM.getResult<ScalarEvolutionAnalysis>(F));
6669db0c572SArthur Eubanks   return PreservedAnalyses::all();
6679db0c572SArthur Eubanks }
668