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