xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/Delinearization.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---- Delinearization.cpp - MultiDimensional Index Delinearization ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This implements an analysis pass that tries to delinearize all GEP
100b57cec5SDimitry Andric // instructions in all loops using the SCEV analysis functionality. This pass is
110b57cec5SDimitry Andric // only used for testing purposes: if your pass needs delinearization, please
120b57cec5SDimitry Andric // use the on-demand SCEVAddRecExpr::delinearize() function.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric 
16e8d8bef9SDimitry Andric #include "llvm/Analysis/Delinearization.h"
170b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
180b57cec5SDimitry Andric #include "llvm/Analysis/Passes.h"
190b57cec5SDimitry Andric #include "llvm/Analysis/ScalarEvolution.h"
20349cc55cSDimitry Andric #include "llvm/Analysis/ScalarEvolutionDivision.h"
210b57cec5SDimitry Andric #include "llvm/Analysis/ScalarEvolutionExpressions.h"
220b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
230b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
240b57cec5SDimitry Andric #include "llvm/IR/Function.h"
250b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h"
260b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
27e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #define DL_NAME "delinearize"
340b57cec5SDimitry Andric #define DEBUG_TYPE DL_NAME
350b57cec5SDimitry Andric 
36349cc55cSDimitry Andric // Return true when S contains at least an undef value.
37349cc55cSDimitry Andric static inline bool containsUndefs(const SCEV *S) {
38349cc55cSDimitry Andric   return SCEVExprContains(S, [](const SCEV *S) {
39349cc55cSDimitry Andric     if (const auto *SU = dyn_cast<SCEVUnknown>(S))
40349cc55cSDimitry Andric       return isa<UndefValue>(SU->getValue());
41349cc55cSDimitry Andric     return false;
42349cc55cSDimitry Andric   });
43349cc55cSDimitry Andric }
44349cc55cSDimitry Andric 
45349cc55cSDimitry Andric namespace {
46349cc55cSDimitry Andric 
47349cc55cSDimitry Andric // Collect all steps of SCEV expressions.
48349cc55cSDimitry Andric struct SCEVCollectStrides {
49349cc55cSDimitry Andric   ScalarEvolution &SE;
50349cc55cSDimitry Andric   SmallVectorImpl<const SCEV *> &Strides;
51349cc55cSDimitry Andric 
52349cc55cSDimitry Andric   SCEVCollectStrides(ScalarEvolution &SE, SmallVectorImpl<const SCEV *> &S)
53349cc55cSDimitry Andric       : SE(SE), Strides(S) {}
54349cc55cSDimitry Andric 
55349cc55cSDimitry Andric   bool follow(const SCEV *S) {
56349cc55cSDimitry Andric     if (const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S))
57349cc55cSDimitry Andric       Strides.push_back(AR->getStepRecurrence(SE));
58349cc55cSDimitry Andric     return true;
59349cc55cSDimitry Andric   }
60349cc55cSDimitry Andric 
61349cc55cSDimitry Andric   bool isDone() const { return false; }
62349cc55cSDimitry Andric };
63349cc55cSDimitry Andric 
64349cc55cSDimitry Andric // Collect all SCEVUnknown and SCEVMulExpr expressions.
65349cc55cSDimitry Andric struct SCEVCollectTerms {
66349cc55cSDimitry Andric   SmallVectorImpl<const SCEV *> &Terms;
67349cc55cSDimitry Andric 
68349cc55cSDimitry Andric   SCEVCollectTerms(SmallVectorImpl<const SCEV *> &T) : Terms(T) {}
69349cc55cSDimitry Andric 
70349cc55cSDimitry Andric   bool follow(const SCEV *S) {
71349cc55cSDimitry Andric     if (isa<SCEVUnknown>(S) || isa<SCEVMulExpr>(S) ||
72349cc55cSDimitry Andric         isa<SCEVSignExtendExpr>(S)) {
73349cc55cSDimitry Andric       if (!containsUndefs(S))
74349cc55cSDimitry Andric         Terms.push_back(S);
75349cc55cSDimitry Andric 
76349cc55cSDimitry Andric       // Stop recursion: once we collected a term, do not walk its operands.
77349cc55cSDimitry Andric       return false;
78349cc55cSDimitry Andric     }
79349cc55cSDimitry Andric 
80349cc55cSDimitry Andric     // Keep looking.
81349cc55cSDimitry Andric     return true;
82349cc55cSDimitry Andric   }
83349cc55cSDimitry Andric 
84349cc55cSDimitry Andric   bool isDone() const { return false; }
85349cc55cSDimitry Andric };
86349cc55cSDimitry Andric 
87349cc55cSDimitry Andric // Check if a SCEV contains an AddRecExpr.
88349cc55cSDimitry Andric struct SCEVHasAddRec {
89349cc55cSDimitry Andric   bool &ContainsAddRec;
90349cc55cSDimitry Andric 
91349cc55cSDimitry Andric   SCEVHasAddRec(bool &ContainsAddRec) : ContainsAddRec(ContainsAddRec) {
92349cc55cSDimitry Andric     ContainsAddRec = false;
93349cc55cSDimitry Andric   }
94349cc55cSDimitry Andric 
95349cc55cSDimitry Andric   bool follow(const SCEV *S) {
96349cc55cSDimitry Andric     if (isa<SCEVAddRecExpr>(S)) {
97349cc55cSDimitry Andric       ContainsAddRec = true;
98349cc55cSDimitry Andric 
99349cc55cSDimitry Andric       // Stop recursion: once we collected a term, do not walk its operands.
100349cc55cSDimitry Andric       return false;
101349cc55cSDimitry Andric     }
102349cc55cSDimitry Andric 
103349cc55cSDimitry Andric     // Keep looking.
104349cc55cSDimitry Andric     return true;
105349cc55cSDimitry Andric   }
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric   bool isDone() const { return false; }
108349cc55cSDimitry Andric };
109349cc55cSDimitry Andric 
110349cc55cSDimitry Andric // Find factors that are multiplied with an expression that (possibly as a
111349cc55cSDimitry Andric // subexpression) contains an AddRecExpr. In the expression:
112349cc55cSDimitry Andric //
113349cc55cSDimitry Andric //  8 * (100 +  %p * %q * (%a + {0, +, 1}_loop))
114349cc55cSDimitry Andric //
115349cc55cSDimitry Andric // "%p * %q" are factors multiplied by the expression "(%a + {0, +, 1}_loop)"
116349cc55cSDimitry Andric // that contains the AddRec {0, +, 1}_loop. %p * %q are likely to be array size
117349cc55cSDimitry Andric // parameters as they form a product with an induction variable.
118349cc55cSDimitry Andric //
119349cc55cSDimitry Andric // This collector expects all array size parameters to be in the same MulExpr.
120349cc55cSDimitry Andric // It might be necessary to later add support for collecting parameters that are
121349cc55cSDimitry Andric // spread over different nested MulExpr.
122349cc55cSDimitry Andric struct SCEVCollectAddRecMultiplies {
123349cc55cSDimitry Andric   SmallVectorImpl<const SCEV *> &Terms;
124349cc55cSDimitry Andric   ScalarEvolution &SE;
125349cc55cSDimitry Andric 
126349cc55cSDimitry Andric   SCEVCollectAddRecMultiplies(SmallVectorImpl<const SCEV *> &T,
127349cc55cSDimitry Andric                               ScalarEvolution &SE)
128349cc55cSDimitry Andric       : Terms(T), SE(SE) {}
129349cc55cSDimitry Andric 
130349cc55cSDimitry Andric   bool follow(const SCEV *S) {
131349cc55cSDimitry Andric     if (auto *Mul = dyn_cast<SCEVMulExpr>(S)) {
132349cc55cSDimitry Andric       bool HasAddRec = false;
133349cc55cSDimitry Andric       SmallVector<const SCEV *, 0> Operands;
134fcaf7f86SDimitry Andric       for (const auto *Op : Mul->operands()) {
135349cc55cSDimitry Andric         const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(Op);
136349cc55cSDimitry Andric         if (Unknown && !isa<CallInst>(Unknown->getValue())) {
137349cc55cSDimitry Andric           Operands.push_back(Op);
138349cc55cSDimitry Andric         } else if (Unknown) {
139349cc55cSDimitry Andric           HasAddRec = true;
140349cc55cSDimitry Andric         } else {
141349cc55cSDimitry Andric           bool ContainsAddRec = false;
142349cc55cSDimitry Andric           SCEVHasAddRec ContiansAddRec(ContainsAddRec);
143349cc55cSDimitry Andric           visitAll(Op, ContiansAddRec);
144349cc55cSDimitry Andric           HasAddRec |= ContainsAddRec;
145349cc55cSDimitry Andric         }
146349cc55cSDimitry Andric       }
147349cc55cSDimitry Andric       if (Operands.size() == 0)
148349cc55cSDimitry Andric         return true;
149349cc55cSDimitry Andric 
150349cc55cSDimitry Andric       if (!HasAddRec)
151349cc55cSDimitry Andric         return false;
152349cc55cSDimitry Andric 
153349cc55cSDimitry Andric       Terms.push_back(SE.getMulExpr(Operands));
154349cc55cSDimitry Andric       // Stop recursion: once we collected a term, do not walk its operands.
155349cc55cSDimitry Andric       return false;
156349cc55cSDimitry Andric     }
157349cc55cSDimitry Andric 
158349cc55cSDimitry Andric     // Keep looking.
159349cc55cSDimitry Andric     return true;
160349cc55cSDimitry Andric   }
161349cc55cSDimitry Andric 
162349cc55cSDimitry Andric   bool isDone() const { return false; }
163349cc55cSDimitry Andric };
164349cc55cSDimitry Andric 
165349cc55cSDimitry Andric } // end anonymous namespace
166349cc55cSDimitry Andric 
167349cc55cSDimitry Andric /// Find parametric terms in this SCEVAddRecExpr. We first for parameters in
168349cc55cSDimitry Andric /// two places:
169349cc55cSDimitry Andric ///   1) The strides of AddRec expressions.
170349cc55cSDimitry Andric ///   2) Unknowns that are multiplied with AddRec expressions.
171349cc55cSDimitry Andric void llvm::collectParametricTerms(ScalarEvolution &SE, const SCEV *Expr,
172349cc55cSDimitry Andric                                   SmallVectorImpl<const SCEV *> &Terms) {
173349cc55cSDimitry Andric   SmallVector<const SCEV *, 4> Strides;
174349cc55cSDimitry Andric   SCEVCollectStrides StrideCollector(SE, Strides);
175349cc55cSDimitry Andric   visitAll(Expr, StrideCollector);
176349cc55cSDimitry Andric 
177349cc55cSDimitry Andric   LLVM_DEBUG({
178349cc55cSDimitry Andric     dbgs() << "Strides:\n";
179349cc55cSDimitry Andric     for (const SCEV *S : Strides)
180349cc55cSDimitry Andric       dbgs() << *S << "\n";
181349cc55cSDimitry Andric   });
182349cc55cSDimitry Andric 
183349cc55cSDimitry Andric   for (const SCEV *S : Strides) {
184349cc55cSDimitry Andric     SCEVCollectTerms TermCollector(Terms);
185349cc55cSDimitry Andric     visitAll(S, TermCollector);
186349cc55cSDimitry Andric   }
187349cc55cSDimitry Andric 
188349cc55cSDimitry Andric   LLVM_DEBUG({
189349cc55cSDimitry Andric     dbgs() << "Terms:\n";
190349cc55cSDimitry Andric     for (const SCEV *T : Terms)
191349cc55cSDimitry Andric       dbgs() << *T << "\n";
192349cc55cSDimitry Andric   });
193349cc55cSDimitry Andric 
194349cc55cSDimitry Andric   SCEVCollectAddRecMultiplies MulCollector(Terms, SE);
195349cc55cSDimitry Andric   visitAll(Expr, MulCollector);
196349cc55cSDimitry Andric }
197349cc55cSDimitry Andric 
198349cc55cSDimitry Andric static bool findArrayDimensionsRec(ScalarEvolution &SE,
199349cc55cSDimitry Andric                                    SmallVectorImpl<const SCEV *> &Terms,
200349cc55cSDimitry Andric                                    SmallVectorImpl<const SCEV *> &Sizes) {
201349cc55cSDimitry Andric   int Last = Terms.size() - 1;
202349cc55cSDimitry Andric   const SCEV *Step = Terms[Last];
203349cc55cSDimitry Andric 
204349cc55cSDimitry Andric   // End of recursion.
205349cc55cSDimitry Andric   if (Last == 0) {
206349cc55cSDimitry Andric     if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Step)) {
207349cc55cSDimitry Andric       SmallVector<const SCEV *, 2> Qs;
208349cc55cSDimitry Andric       for (const SCEV *Op : M->operands())
209349cc55cSDimitry Andric         if (!isa<SCEVConstant>(Op))
210349cc55cSDimitry Andric           Qs.push_back(Op);
211349cc55cSDimitry Andric 
212349cc55cSDimitry Andric       Step = SE.getMulExpr(Qs);
213349cc55cSDimitry Andric     }
214349cc55cSDimitry Andric 
215349cc55cSDimitry Andric     Sizes.push_back(Step);
216349cc55cSDimitry Andric     return true;
217349cc55cSDimitry Andric   }
218349cc55cSDimitry Andric 
219349cc55cSDimitry Andric   for (const SCEV *&Term : Terms) {
220349cc55cSDimitry Andric     // Normalize the terms before the next call to findArrayDimensionsRec.
221349cc55cSDimitry Andric     const SCEV *Q, *R;
222349cc55cSDimitry Andric     SCEVDivision::divide(SE, Term, Step, &Q, &R);
223349cc55cSDimitry Andric 
224349cc55cSDimitry Andric     // Bail out when GCD does not evenly divide one of the terms.
225349cc55cSDimitry Andric     if (!R->isZero())
226349cc55cSDimitry Andric       return false;
227349cc55cSDimitry Andric 
228349cc55cSDimitry Andric     Term = Q;
229349cc55cSDimitry Andric   }
230349cc55cSDimitry Andric 
231349cc55cSDimitry Andric   // Remove all SCEVConstants.
232349cc55cSDimitry Andric   erase_if(Terms, [](const SCEV *E) { return isa<SCEVConstant>(E); });
233349cc55cSDimitry Andric 
234349cc55cSDimitry Andric   if (Terms.size() > 0)
235349cc55cSDimitry Andric     if (!findArrayDimensionsRec(SE, Terms, Sizes))
236349cc55cSDimitry Andric       return false;
237349cc55cSDimitry Andric 
238349cc55cSDimitry Andric   Sizes.push_back(Step);
239349cc55cSDimitry Andric   return true;
240349cc55cSDimitry Andric }
241349cc55cSDimitry Andric 
242349cc55cSDimitry Andric // Returns true when one of the SCEVs of Terms contains a SCEVUnknown parameter.
243349cc55cSDimitry Andric static inline bool containsParameters(SmallVectorImpl<const SCEV *> &Terms) {
244349cc55cSDimitry Andric   for (const SCEV *T : Terms)
245349cc55cSDimitry Andric     if (SCEVExprContains(T, [](const SCEV *S) { return isa<SCEVUnknown>(S); }))
246349cc55cSDimitry Andric       return true;
247349cc55cSDimitry Andric 
248349cc55cSDimitry Andric   return false;
249349cc55cSDimitry Andric }
250349cc55cSDimitry Andric 
251349cc55cSDimitry Andric // Return the number of product terms in S.
252349cc55cSDimitry Andric static inline int numberOfTerms(const SCEV *S) {
253349cc55cSDimitry Andric   if (const SCEVMulExpr *Expr = dyn_cast<SCEVMulExpr>(S))
254349cc55cSDimitry Andric     return Expr->getNumOperands();
255349cc55cSDimitry Andric   return 1;
256349cc55cSDimitry Andric }
257349cc55cSDimitry Andric 
258349cc55cSDimitry Andric static const SCEV *removeConstantFactors(ScalarEvolution &SE, const SCEV *T) {
259349cc55cSDimitry Andric   if (isa<SCEVConstant>(T))
260349cc55cSDimitry Andric     return nullptr;
261349cc55cSDimitry Andric 
262349cc55cSDimitry Andric   if (isa<SCEVUnknown>(T))
263349cc55cSDimitry Andric     return T;
264349cc55cSDimitry Andric 
265349cc55cSDimitry Andric   if (const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(T)) {
266349cc55cSDimitry Andric     SmallVector<const SCEV *, 2> Factors;
267349cc55cSDimitry Andric     for (const SCEV *Op : M->operands())
268349cc55cSDimitry Andric       if (!isa<SCEVConstant>(Op))
269349cc55cSDimitry Andric         Factors.push_back(Op);
270349cc55cSDimitry Andric 
271349cc55cSDimitry Andric     return SE.getMulExpr(Factors);
272349cc55cSDimitry Andric   }
273349cc55cSDimitry Andric 
274349cc55cSDimitry Andric   return T;
275349cc55cSDimitry Andric }
276349cc55cSDimitry Andric 
277349cc55cSDimitry Andric void llvm::findArrayDimensions(ScalarEvolution &SE,
278349cc55cSDimitry Andric                                SmallVectorImpl<const SCEV *> &Terms,
279349cc55cSDimitry Andric                                SmallVectorImpl<const SCEV *> &Sizes,
280349cc55cSDimitry Andric                                const SCEV *ElementSize) {
281349cc55cSDimitry Andric   if (Terms.size() < 1 || !ElementSize)
282349cc55cSDimitry Andric     return;
283349cc55cSDimitry Andric 
284349cc55cSDimitry Andric   // Early return when Terms do not contain parameters: we do not delinearize
285349cc55cSDimitry Andric   // non parametric SCEVs.
286349cc55cSDimitry Andric   if (!containsParameters(Terms))
287349cc55cSDimitry Andric     return;
288349cc55cSDimitry Andric 
289349cc55cSDimitry Andric   LLVM_DEBUG({
290349cc55cSDimitry Andric     dbgs() << "Terms:\n";
291349cc55cSDimitry Andric     for (const SCEV *T : Terms)
292349cc55cSDimitry Andric       dbgs() << *T << "\n";
293349cc55cSDimitry Andric   });
294349cc55cSDimitry Andric 
295349cc55cSDimitry Andric   // Remove duplicates.
296349cc55cSDimitry Andric   array_pod_sort(Terms.begin(), Terms.end());
297*0fca6ea1SDimitry Andric   Terms.erase(llvm::unique(Terms), Terms.end());
298349cc55cSDimitry Andric 
299349cc55cSDimitry Andric   // Put larger terms first.
300349cc55cSDimitry Andric   llvm::sort(Terms, [](const SCEV *LHS, const SCEV *RHS) {
301349cc55cSDimitry Andric     return numberOfTerms(LHS) > numberOfTerms(RHS);
302349cc55cSDimitry Andric   });
303349cc55cSDimitry Andric 
304349cc55cSDimitry Andric   // Try to divide all terms by the element size. If term is not divisible by
305349cc55cSDimitry Andric   // element size, proceed with the original term.
306349cc55cSDimitry Andric   for (const SCEV *&Term : Terms) {
307349cc55cSDimitry Andric     const SCEV *Q, *R;
308349cc55cSDimitry Andric     SCEVDivision::divide(SE, Term, ElementSize, &Q, &R);
309349cc55cSDimitry Andric     if (!Q->isZero())
310349cc55cSDimitry Andric       Term = Q;
311349cc55cSDimitry Andric   }
312349cc55cSDimitry Andric 
313349cc55cSDimitry Andric   SmallVector<const SCEV *, 4> NewTerms;
314349cc55cSDimitry Andric 
315349cc55cSDimitry Andric   // Remove constant factors.
316349cc55cSDimitry Andric   for (const SCEV *T : Terms)
317349cc55cSDimitry Andric     if (const SCEV *NewT = removeConstantFactors(SE, T))
318349cc55cSDimitry Andric       NewTerms.push_back(NewT);
319349cc55cSDimitry Andric 
320349cc55cSDimitry Andric   LLVM_DEBUG({
321349cc55cSDimitry Andric     dbgs() << "Terms after sorting:\n";
322349cc55cSDimitry Andric     for (const SCEV *T : NewTerms)
323349cc55cSDimitry Andric       dbgs() << *T << "\n";
324349cc55cSDimitry Andric   });
325349cc55cSDimitry Andric 
326349cc55cSDimitry Andric   if (NewTerms.empty() || !findArrayDimensionsRec(SE, NewTerms, Sizes)) {
327349cc55cSDimitry Andric     Sizes.clear();
328349cc55cSDimitry Andric     return;
329349cc55cSDimitry Andric   }
330349cc55cSDimitry Andric 
331349cc55cSDimitry Andric   // The last element to be pushed into Sizes is the size of an element.
332349cc55cSDimitry Andric   Sizes.push_back(ElementSize);
333349cc55cSDimitry Andric 
334349cc55cSDimitry Andric   LLVM_DEBUG({
335349cc55cSDimitry Andric     dbgs() << "Sizes:\n";
336349cc55cSDimitry Andric     for (const SCEV *S : Sizes)
337349cc55cSDimitry Andric       dbgs() << *S << "\n";
338349cc55cSDimitry Andric   });
339349cc55cSDimitry Andric }
340349cc55cSDimitry Andric 
341349cc55cSDimitry Andric void llvm::computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
342349cc55cSDimitry Andric                                   SmallVectorImpl<const SCEV *> &Subscripts,
343349cc55cSDimitry Andric                                   SmallVectorImpl<const SCEV *> &Sizes) {
344349cc55cSDimitry Andric   // Early exit in case this SCEV is not an affine multivariate function.
345349cc55cSDimitry Andric   if (Sizes.empty())
346349cc55cSDimitry Andric     return;
347349cc55cSDimitry Andric 
348349cc55cSDimitry Andric   if (auto *AR = dyn_cast<SCEVAddRecExpr>(Expr))
349349cc55cSDimitry Andric     if (!AR->isAffine())
350349cc55cSDimitry Andric       return;
351349cc55cSDimitry Andric 
352349cc55cSDimitry Andric   const SCEV *Res = Expr;
353349cc55cSDimitry Andric   int Last = Sizes.size() - 1;
354349cc55cSDimitry Andric   for (int i = Last; i >= 0; i--) {
355349cc55cSDimitry Andric     const SCEV *Q, *R;
356349cc55cSDimitry Andric     SCEVDivision::divide(SE, Res, Sizes[i], &Q, &R);
357349cc55cSDimitry Andric 
358349cc55cSDimitry Andric     LLVM_DEBUG({
359349cc55cSDimitry Andric       dbgs() << "Res: " << *Res << "\n";
360349cc55cSDimitry Andric       dbgs() << "Sizes[i]: " << *Sizes[i] << "\n";
361349cc55cSDimitry Andric       dbgs() << "Res divided by Sizes[i]:\n";
362349cc55cSDimitry Andric       dbgs() << "Quotient: " << *Q << "\n";
363349cc55cSDimitry Andric       dbgs() << "Remainder: " << *R << "\n";
364349cc55cSDimitry Andric     });
365349cc55cSDimitry Andric 
366349cc55cSDimitry Andric     Res = Q;
367349cc55cSDimitry Andric 
368349cc55cSDimitry Andric     // Do not record the last subscript corresponding to the size of elements in
369349cc55cSDimitry Andric     // the array.
370349cc55cSDimitry Andric     if (i == Last) {
371349cc55cSDimitry Andric 
372349cc55cSDimitry Andric       // Bail out if the byte offset is non-zero.
373349cc55cSDimitry Andric       if (!R->isZero()) {
374349cc55cSDimitry Andric         Subscripts.clear();
375349cc55cSDimitry Andric         Sizes.clear();
376349cc55cSDimitry Andric         return;
377349cc55cSDimitry Andric       }
378349cc55cSDimitry Andric 
379349cc55cSDimitry Andric       continue;
380349cc55cSDimitry Andric     }
381349cc55cSDimitry Andric 
382349cc55cSDimitry Andric     // Record the access function for the current subscript.
383349cc55cSDimitry Andric     Subscripts.push_back(R);
384349cc55cSDimitry Andric   }
385349cc55cSDimitry Andric 
386349cc55cSDimitry Andric   // Also push in last position the remainder of the last division: it will be
387349cc55cSDimitry Andric   // the access function of the innermost dimension.
388349cc55cSDimitry Andric   Subscripts.push_back(Res);
389349cc55cSDimitry Andric 
390349cc55cSDimitry Andric   std::reverse(Subscripts.begin(), Subscripts.end());
391349cc55cSDimitry Andric 
392349cc55cSDimitry Andric   LLVM_DEBUG({
393349cc55cSDimitry Andric     dbgs() << "Subscripts:\n";
394349cc55cSDimitry Andric     for (const SCEV *S : Subscripts)
395349cc55cSDimitry Andric       dbgs() << *S << "\n";
396349cc55cSDimitry Andric   });
397349cc55cSDimitry Andric }
398349cc55cSDimitry Andric 
399349cc55cSDimitry Andric /// Splits the SCEV into two vectors of SCEVs representing the subscripts and
400349cc55cSDimitry Andric /// sizes of an array access. Returns the remainder of the delinearization that
401349cc55cSDimitry Andric /// is the offset start of the array.  The SCEV->delinearize algorithm computes
402349cc55cSDimitry Andric /// the multiples of SCEV coefficients: that is a pattern matching of sub
403349cc55cSDimitry Andric /// expressions in the stride and base of a SCEV corresponding to the
404349cc55cSDimitry Andric /// computation of a GCD (greatest common divisor) of base and stride.  When
405349cc55cSDimitry Andric /// SCEV->delinearize fails, it returns the SCEV unchanged.
406349cc55cSDimitry Andric ///
407349cc55cSDimitry Andric /// For example: when analyzing the memory access A[i][j][k] in this loop nest
408349cc55cSDimitry Andric ///
409349cc55cSDimitry Andric ///  void foo(long n, long m, long o, double A[n][m][o]) {
410349cc55cSDimitry Andric ///
411349cc55cSDimitry Andric ///    for (long i = 0; i < n; i++)
412349cc55cSDimitry Andric ///      for (long j = 0; j < m; j++)
413349cc55cSDimitry Andric ///        for (long k = 0; k < o; k++)
414349cc55cSDimitry Andric ///          A[i][j][k] = 1.0;
415349cc55cSDimitry Andric ///  }
416349cc55cSDimitry Andric ///
417349cc55cSDimitry Andric /// the delinearization input is the following AddRec SCEV:
418349cc55cSDimitry Andric ///
419349cc55cSDimitry Andric ///  AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
420349cc55cSDimitry Andric ///
421349cc55cSDimitry Andric /// From this SCEV, we are able to say that the base offset of the access is %A
422349cc55cSDimitry Andric /// because it appears as an offset that does not divide any of the strides in
423349cc55cSDimitry Andric /// the loops:
424349cc55cSDimitry Andric ///
425349cc55cSDimitry Andric ///  CHECK: Base offset: %A
426349cc55cSDimitry Andric ///
427349cc55cSDimitry Andric /// and then SCEV->delinearize determines the size of some of the dimensions of
428349cc55cSDimitry Andric /// the array as these are the multiples by which the strides are happening:
429349cc55cSDimitry Andric ///
430349cc55cSDimitry Andric ///  CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double)
431349cc55cSDimitry Andric ///  bytes.
432349cc55cSDimitry Andric ///
433349cc55cSDimitry Andric /// Note that the outermost dimension remains of UnknownSize because there are
434349cc55cSDimitry Andric /// no strides that would help identifying the size of the last dimension: when
435349cc55cSDimitry Andric /// the array has been statically allocated, one could compute the size of that
436349cc55cSDimitry Andric /// dimension by dividing the overall size of the array by the size of the known
437349cc55cSDimitry Andric /// dimensions: %m * %o * 8.
438349cc55cSDimitry Andric ///
439349cc55cSDimitry Andric /// Finally delinearize provides the access functions for the array reference
440349cc55cSDimitry Andric /// that does correspond to A[i][j][k] of the above C testcase:
441349cc55cSDimitry Andric ///
442349cc55cSDimitry Andric ///  CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
443349cc55cSDimitry Andric ///
444349cc55cSDimitry Andric /// The testcases are checking the output of a function pass:
445349cc55cSDimitry Andric /// DelinearizationPass that walks through all loads and stores of a function
446349cc55cSDimitry Andric /// asking for the SCEV of the memory access with respect to all enclosing
447349cc55cSDimitry Andric /// loops, calling SCEV->delinearize on that and printing the results.
448349cc55cSDimitry Andric void llvm::delinearize(ScalarEvolution &SE, const SCEV *Expr,
449349cc55cSDimitry Andric                        SmallVectorImpl<const SCEV *> &Subscripts,
450349cc55cSDimitry Andric                        SmallVectorImpl<const SCEV *> &Sizes,
451349cc55cSDimitry Andric                        const SCEV *ElementSize) {
452349cc55cSDimitry Andric   // First step: collect parametric terms.
453349cc55cSDimitry Andric   SmallVector<const SCEV *, 4> Terms;
454349cc55cSDimitry Andric   collectParametricTerms(SE, Expr, Terms);
455349cc55cSDimitry Andric 
456349cc55cSDimitry Andric   if (Terms.empty())
457349cc55cSDimitry Andric     return;
458349cc55cSDimitry Andric 
459349cc55cSDimitry Andric   // Second step: find subscript sizes.
460349cc55cSDimitry Andric   findArrayDimensions(SE, Terms, Sizes, ElementSize);
461349cc55cSDimitry Andric 
462349cc55cSDimitry Andric   if (Sizes.empty())
463349cc55cSDimitry Andric     return;
464349cc55cSDimitry Andric 
465349cc55cSDimitry Andric   // Third step: compute the access functions for each subscript.
466349cc55cSDimitry Andric   computeAccessFunctions(SE, Expr, Subscripts, Sizes);
467349cc55cSDimitry Andric 
468349cc55cSDimitry Andric   if (Subscripts.empty())
469349cc55cSDimitry Andric     return;
470349cc55cSDimitry Andric 
471349cc55cSDimitry Andric   LLVM_DEBUG({
472349cc55cSDimitry Andric     dbgs() << "succeeded to delinearize " << *Expr << "\n";
473349cc55cSDimitry Andric     dbgs() << "ArrayDecl[UnknownSize]";
474349cc55cSDimitry Andric     for (const SCEV *S : Sizes)
475349cc55cSDimitry Andric       dbgs() << "[" << *S << "]";
476349cc55cSDimitry Andric 
477349cc55cSDimitry Andric     dbgs() << "\nArrayRef";
478349cc55cSDimitry Andric     for (const SCEV *S : Subscripts)
479349cc55cSDimitry Andric       dbgs() << "[" << *S << "]";
480349cc55cSDimitry Andric     dbgs() << "\n";
481349cc55cSDimitry Andric   });
482349cc55cSDimitry Andric }
483349cc55cSDimitry Andric 
484349cc55cSDimitry Andric bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
485349cc55cSDimitry Andric                                       const GetElementPtrInst *GEP,
486349cc55cSDimitry Andric                                       SmallVectorImpl<const SCEV *> &Subscripts,
487349cc55cSDimitry Andric                                       SmallVectorImpl<int> &Sizes) {
488349cc55cSDimitry Andric   assert(Subscripts.empty() && Sizes.empty() &&
489349cc55cSDimitry Andric          "Expected output lists to be empty on entry to this function.");
490349cc55cSDimitry Andric   assert(GEP && "getIndexExpressionsFromGEP called with a null GEP");
491349cc55cSDimitry Andric   Type *Ty = nullptr;
492349cc55cSDimitry Andric   bool DroppedFirstDim = false;
493349cc55cSDimitry Andric   for (unsigned i = 1; i < GEP->getNumOperands(); i++) {
494349cc55cSDimitry Andric     const SCEV *Expr = SE.getSCEV(GEP->getOperand(i));
495349cc55cSDimitry Andric     if (i == 1) {
496349cc55cSDimitry Andric       Ty = GEP->getSourceElementType();
497349cc55cSDimitry Andric       if (auto *Const = dyn_cast<SCEVConstant>(Expr))
498349cc55cSDimitry Andric         if (Const->getValue()->isZero()) {
499349cc55cSDimitry Andric           DroppedFirstDim = true;
500349cc55cSDimitry Andric           continue;
501349cc55cSDimitry Andric         }
502349cc55cSDimitry Andric       Subscripts.push_back(Expr);
503349cc55cSDimitry Andric       continue;
504349cc55cSDimitry Andric     }
505349cc55cSDimitry Andric 
506349cc55cSDimitry Andric     auto *ArrayTy = dyn_cast<ArrayType>(Ty);
507349cc55cSDimitry Andric     if (!ArrayTy) {
508349cc55cSDimitry Andric       Subscripts.clear();
509349cc55cSDimitry Andric       Sizes.clear();
510349cc55cSDimitry Andric       return false;
511349cc55cSDimitry Andric     }
512349cc55cSDimitry Andric 
513349cc55cSDimitry Andric     Subscripts.push_back(Expr);
514349cc55cSDimitry Andric     if (!(DroppedFirstDim && i == 2))
515349cc55cSDimitry Andric       Sizes.push_back(ArrayTy->getNumElements());
516349cc55cSDimitry Andric 
517349cc55cSDimitry Andric     Ty = ArrayTy->getElementType();
518349cc55cSDimitry Andric   }
519349cc55cSDimitry Andric   return !Subscripts.empty();
520349cc55cSDimitry Andric }
521349cc55cSDimitry Andric 
52281ad6265SDimitry Andric bool llvm::tryDelinearizeFixedSizeImpl(
52381ad6265SDimitry Andric     ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn,
52481ad6265SDimitry Andric     SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<int> &Sizes) {
52581ad6265SDimitry Andric   Value *SrcPtr = getLoadStorePointerOperand(Inst);
52681ad6265SDimitry Andric 
52781ad6265SDimitry Andric   // Check the simple case where the array dimensions are fixed size.
52881ad6265SDimitry Andric   auto *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr);
52981ad6265SDimitry Andric   if (!SrcGEP)
53081ad6265SDimitry Andric     return false;
53181ad6265SDimitry Andric 
53281ad6265SDimitry Andric   getIndexExpressionsFromGEP(*SE, SrcGEP, Subscripts, Sizes);
53381ad6265SDimitry Andric 
53481ad6265SDimitry Andric   // Check that the two size arrays are non-empty and equal in length and
53581ad6265SDimitry Andric   // value.
53681ad6265SDimitry Andric   // TODO: it would be better to let the caller to clear Subscripts, similar
53781ad6265SDimitry Andric   // to how we handle Sizes.
53881ad6265SDimitry Andric   if (Sizes.empty() || Subscripts.size() <= 1) {
53981ad6265SDimitry Andric     Subscripts.clear();
54081ad6265SDimitry Andric     return false;
54181ad6265SDimitry Andric   }
54281ad6265SDimitry Andric 
54381ad6265SDimitry Andric   // Check that for identical base pointers we do not miss index offsets
54481ad6265SDimitry Andric   // that have been added before this GEP is applied.
54581ad6265SDimitry Andric   Value *SrcBasePtr = SrcGEP->getOperand(0)->stripPointerCasts();
54681ad6265SDimitry Andric   const SCEVUnknown *SrcBase =
54781ad6265SDimitry Andric       dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFn));
54881ad6265SDimitry Andric   if (!SrcBase || SrcBasePtr != SrcBase->getValue()) {
54981ad6265SDimitry Andric     Subscripts.clear();
55081ad6265SDimitry Andric     return false;
55181ad6265SDimitry Andric   }
55281ad6265SDimitry Andric 
55381ad6265SDimitry Andric   assert(Subscripts.size() == Sizes.size() + 1 &&
55481ad6265SDimitry Andric          "Expected equal number of entries in the list of size and "
55581ad6265SDimitry Andric          "subscript.");
55681ad6265SDimitry Andric 
55781ad6265SDimitry Andric   return true;
55881ad6265SDimitry Andric }
55981ad6265SDimitry Andric 
5600b57cec5SDimitry Andric namespace {
5610b57cec5SDimitry Andric 
562e8d8bef9SDimitry Andric void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
563e8d8bef9SDimitry Andric                           ScalarEvolution *SE) {
5640b57cec5SDimitry Andric   O << "Delinearization on function " << F->getName() << ":\n";
565fe6060f1SDimitry Andric   for (Instruction &Inst : instructions(F)) {
5660b57cec5SDimitry Andric     // Only analyze loads and stores.
567fe6060f1SDimitry Andric     if (!isa<StoreInst>(&Inst) && !isa<LoadInst>(&Inst) &&
568fe6060f1SDimitry Andric         !isa<GetElementPtrInst>(&Inst))
5690b57cec5SDimitry Andric       continue;
5700b57cec5SDimitry Andric 
571fe6060f1SDimitry Andric     const BasicBlock *BB = Inst.getParent();
5720b57cec5SDimitry Andric     // Delinearize the memory access as analyzed in all the surrounding loops.
5730b57cec5SDimitry Andric     // Do not analyze memory accesses outside loops.
5740b57cec5SDimitry Andric     for (Loop *L = LI->getLoopFor(BB); L != nullptr; L = L->getParentLoop()) {
575fe6060f1SDimitry Andric       const SCEV *AccessFn = SE->getSCEVAtScope(getPointerOperand(&Inst), L);
5760b57cec5SDimitry Andric 
5770b57cec5SDimitry Andric       const SCEVUnknown *BasePointer =
5780b57cec5SDimitry Andric           dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFn));
5790b57cec5SDimitry Andric       // Do not delinearize if we cannot find the base pointer.
5800b57cec5SDimitry Andric       if (!BasePointer)
5810b57cec5SDimitry Andric         break;
5820b57cec5SDimitry Andric       AccessFn = SE->getMinusSCEV(AccessFn, BasePointer);
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric       O << "\n";
585fe6060f1SDimitry Andric       O << "Inst:" << Inst << "\n";
5860b57cec5SDimitry Andric       O << "In Loop with Header: " << L->getHeader()->getName() << "\n";
5870b57cec5SDimitry Andric       O << "AccessFunction: " << *AccessFn << "\n";
5880b57cec5SDimitry Andric 
5890b57cec5SDimitry Andric       SmallVector<const SCEV *, 3> Subscripts, Sizes;
590349cc55cSDimitry Andric       delinearize(*SE, AccessFn, Subscripts, Sizes, SE->getElementSize(&Inst));
5910b57cec5SDimitry Andric       if (Subscripts.size() == 0 || Sizes.size() == 0 ||
5920b57cec5SDimitry Andric           Subscripts.size() != Sizes.size()) {
5930b57cec5SDimitry Andric         O << "failed to delinearize\n";
5940b57cec5SDimitry Andric         continue;
5950b57cec5SDimitry Andric       }
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric       O << "Base offset: " << *BasePointer << "\n";
5980b57cec5SDimitry Andric       O << "ArrayDecl[UnknownSize]";
5990b57cec5SDimitry Andric       int Size = Subscripts.size();
6000b57cec5SDimitry Andric       for (int i = 0; i < Size - 1; i++)
6010b57cec5SDimitry Andric         O << "[" << *Sizes[i] << "]";
6020b57cec5SDimitry Andric       O << " with elements of " << *Sizes[Size - 1] << " bytes.\n";
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric       O << "ArrayRef";
6050b57cec5SDimitry Andric       for (int i = 0; i < Size; i++)
6060b57cec5SDimitry Andric         O << "[" << *Subscripts[i] << "]";
6070b57cec5SDimitry Andric       O << "\n";
6080b57cec5SDimitry Andric     }
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric }
6110b57cec5SDimitry Andric 
612e8d8bef9SDimitry Andric } // end anonymous namespace
613e8d8bef9SDimitry Andric 
614e8d8bef9SDimitry Andric DelinearizationPrinterPass::DelinearizationPrinterPass(raw_ostream &OS)
615e8d8bef9SDimitry Andric     : OS(OS) {}
616e8d8bef9SDimitry Andric PreservedAnalyses DelinearizationPrinterPass::run(Function &F,
617e8d8bef9SDimitry Andric                                                   FunctionAnalysisManager &AM) {
618e8d8bef9SDimitry Andric   printDelinearization(OS, &F, &AM.getResult<LoopAnalysis>(F),
619e8d8bef9SDimitry Andric                        &AM.getResult<ScalarEvolutionAnalysis>(F));
620e8d8bef9SDimitry Andric   return PreservedAnalyses::all();
621e8d8bef9SDimitry Andric }
622