llvm.org GIT mirror llvm / 421b2c5
remove constant terms The delinearization is needed only to remove the non linearity induced by expressions involving multiplications of parameters and induction variables. There is no problem in dealing with constant times parameters, or constant times an induction variable. For this reason, the current patch discards all constant terms and multipliers before running the delinearization algorithm on the terms. The only thing remaining in the term expressions are parameters and multiply expressions of parameters: these simplified term expressions are passed to the array shape recognizer that will not recognize constant dimensions anymore: these will be recognized as different strides in parametric subscripts. The only important special case of a constant dimension is the size of elements. Instead of relying on the delinearization to infer the size of an element, compute the element size from the base address type. This is a much more precise way of computing the element size than before, as we would have mixed together the size of an element with the strides of the innermost dimension. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209691 91177308-0d34-0410-b5e6-96231b3b80d8 Sebastian Pop 6 years ago
8 changed file(s) with 145 addition(s) and 39 deletion(s). Raw diff Collapse all Expand all
909909 const Constraint &CurConstraint) const;
910910
911911 bool tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
912 SmallVectorImpl &Pair) const;
912 SmallVectorImpl &Pair,
913 const SCEV *ElementSize) const;
913914
914915 public:
915916 static char ID; // Class identification, replacement for typeinfo
893893 /// indirect operand.
894894 bool hasOperand(const SCEV *S, const SCEV *Op) const;
895895
896 /// Return the size of an element read or written by Inst.
897 const SCEV *getElementSize(Instruction *Inst);
898
896899 /// Compute the array dimensions Sizes from the set of Terms extracted from
897900 /// the memory access function of this SCEVAddRecExpr.
898901 void findArrayDimensions(SmallVectorImpl &Terms,
899 SmallVectorImpl &Sizes) const;
902 SmallVectorImpl &Sizes,
903 const SCEV *ElementSize) const;
900904
901905 bool runOnFunction(Function &F) override;
902906 void releaseMemory() override;
433433 /// Overall, we have: A[][n][m], and the access function: A[j+k][2i][5i].
434434 const SCEV *delinearize(ScalarEvolution &SE,
435435 SmallVectorImpl &Subscripts,
436 SmallVectorImpl &Sizes) const;
436 SmallVectorImpl &Sizes,
437 const SCEV *ElementSize) const;
437438 };
438439
439440 //===--------------------------------------------------------------------===//
107107 O << "AddRec: " << *AR << "\n";
108108
109109 SmallVector Subscripts, Sizes;
110 const SCEV *Res = AR->delinearize(*SE, Subscripts, Sizes);
111 if (Res == AR || Subscripts.size() == 0 || Sizes.size() == 0 ||
110 const SCEV *Res = AR->delinearize(*SE, Subscripts, Sizes, SE->getElementSize(Inst));
111 if (Subscripts.size() == 0 || Sizes.size() == 0 ||
112112 Subscripts.size() != Sizes.size()) {
113113 O << "failed to delinearize\n";
114114 continue;
31793179 /// source and destination array references are recurrences on a nested loop,
31803180 /// this function flattens the nested recurrences into separate recurrences
31813181 /// for each loop level.
3182 bool
3183 DependenceAnalysis::tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
3184 SmallVectorImpl &Pair) const {
3182 bool DependenceAnalysis::tryDelinearize(const SCEV *SrcSCEV,
3183 const SCEV *DstSCEV,
3184 SmallVectorImpl &Pair,
3185 const SCEV *ElementSize) const {
31853186 const SCEVAddRecExpr *SrcAR = dyn_cast(SrcSCEV);
31863187 const SCEVAddRecExpr *DstAR = dyn_cast(DstSCEV);
31873188 if (!SrcAR || !DstAR || !SrcAR->isAffine() || !DstAR->isAffine())
31943195
31953196 // Second step: find subscript sizes.
31963197 SmallVector Sizes;
3197 SE->findArrayDimensions(Terms, Sizes);
3198 SE->findArrayDimensions(Terms, Sizes, ElementSize);
31983199
31993200 // Third step: compute the access functions for each subscript.
32003201 SmallVector SrcSubscripts, DstSubscripts;
33523353 }
33533354
33543355 if (Delinearize && Pairs == 1 && CommonLevels > 1 &&
3355 tryDelinearize(Pair[0].Src, Pair[0].Dst, Pair)) {
3356 tryDelinearize(Pair[0].Src, Pair[0].Dst, Pair, SE->getElementSize(Src))) {
33563357 DEBUG(dbgs() << " delinerized GEP\n");
33573358 Pairs = Pair.size();
33583359 }
37763777 }
37773778
37783779 if (Delinearize && Pairs == 1 && CommonLevels > 1 &&
3779 tryDelinearize(Pair[0].Src, Pair[0].Dst, Pair)) {
3780 tryDelinearize(Pair[0].Src, Pair[0].Dst, Pair, SE->getElementSize(Src))) {
37803781 DEBUG(dbgs() << " delinerized GEP\n");
37813782 Pairs = Pair.size();
37823783 }
69436943 : Terms(T) {}
69446944
69456945 bool follow(const SCEV *S) {
6946 if (isa(S) || isaConstant>(S) || isaMulExpr>(S)) {
6946 if (isa(S) || isaMulExpr>(S)) {
69476947 if (!containsUndefs(S))
69486948 Terms.push_back(S);
69496949
73557355 return 1;
73567356 }
73577357
7358 static const SCEV *removeConstantFactors(ScalarEvolution &SE, const SCEV *T) {
7359 if (isa(T))
7360 return nullptr;
7361
7362 if (isa(T))
7363 return T;
7364
7365 if (const SCEVMulExpr *M = dyn_cast(T)) {
7366 SmallVector Factors;
7367 for (const SCEV *Op : M->operands())
7368 if (!isa(Op))
7369 Factors.push_back(Op);
7370
7371 return SE.getMulExpr(Factors);
7372 }
7373
7374 return T;
7375 }
7376
7377 /// Return the size of an element read or written by Inst.
7378 const SCEV *ScalarEvolution::getElementSize(Instruction *Inst) {
7379 Type *Ty;
7380 if (StoreInst *Store = dyn_cast(Inst))
7381 Ty = Store->getValueOperand()->getType();
7382 else if (LoadInst *Load = dyn_cast(Inst))
7383 Ty = Load->getPointerOperand()->getType();
7384 else
7385 return nullptr;
7386
7387 Type *ETy = getEffectiveSCEVType(PointerType::getUnqual(Ty));
7388 return getSizeOfExpr(ETy, Ty);
7389 }
7390
73587391 /// Second step of delinearization: compute the array dimensions Sizes from the
73597392 /// set of Terms extracted from the memory access function of this SCEVAddRec.
7360 void ScalarEvolution::findArrayDimensions(
7361 SmallVectorImpl &Terms,
7362 SmallVectorImpl &Sizes) const {
7363
7364 if (Terms.size() < 2)
7393 void ScalarEvolution::findArrayDimensions(SmallVectorImpl &Terms,
7394 SmallVectorImpl &Sizes,
7395 const SCEV *ElementSize) const {
7396
7397 if (Terms.size() < 1)
73657398 return;
73667399
73677400 // Early return when Terms do not contain parameters: we do not delinearize
73847417 return numberOfTerms(LHS) > numberOfTerms(RHS);
73857418 });
73867419
7420 ScalarEvolution &SE = *const_cast(this);
7421
7422 // Divide all terms by the element size.
7423 for (const SCEV *&Term : Terms) {
7424 const SCEV *Q, *R;
7425 SCEVDivision::divide(SE, Term, ElementSize, &Q, &R);
7426 Term = Q;
7427 }
7428
7429 SmallVector NewTerms;
7430
7431 // Remove constant factors.
7432 for (const SCEV *T : Terms)
7433 if (const SCEV *NewT = removeConstantFactors(SE, T))
7434 NewTerms.push_back(NewT);
7435
73877436 DEBUG({
73887437 dbgs() << "Terms after sorting:\n";
7389 for (const SCEV *T : Terms)
7438 for (const SCEV *T : NewTerms)
73907439 dbgs() << *T << "\n";
73917440 });
73927441
7393 ScalarEvolution &SE = *const_cast(this);
7394 bool Res = findArrayDimensionsRec(SE, Terms, Sizes);
7395
7396 if (!Res) {
7442 if (NewTerms.empty() ||
7443 !findArrayDimensionsRec(SE, NewTerms, Sizes)) {
73977444 Sizes.clear();
73987445 return;
73997446 }
7447
7448 // The last element to be pushed into Sizes is the size of an element.
7449 Sizes.push_back(ElementSize);
74007450
74017451 DEBUG({
74027452 dbgs() << "Sizes:\n";
74327482
74337483 Res = Q;
74347484
7485 // Do not record the last subscript corresponding to the size of elements in
7486 // the array.
74357487 if (i == Last) {
7436 // Do not record the last subscript corresponding to the size of elements
7437 // in the array.
7488
7489 // Bail out if the remainder is too complex.
7490 if (isa(R))
7491 return nullptr;
7492
74387493 Remainder = R;
74397494 continue;
74407495 }
75067561 /// asking for the SCEV of the memory access with respect to all enclosing
75077562 /// loops, calling SCEV->delinearize on that and printing the results.
75087563
7509 const SCEV *
7510 SCEVAddRecExpr::delinearize(ScalarEvolution &SE,
7511 SmallVectorImpl &Subscripts,
7512 SmallVectorImpl &Sizes) const {
7564 const SCEV *SCEVAddRecExpr::delinearize(
7565 ScalarEvolution &SE, SmallVectorImpl &Subscripts,
7566 SmallVectorImpl &Sizes, const SCEV *ElementSize) const {
75137567 // First step: collect parametric terms.
75147568 SmallVector Terms;
75157569 collectParametricTerms(SE, Terms);
75187572 return nullptr;
75197573
75207574 // Second step: find subscript sizes.
7521 SE.findArrayDimensions(Terms, Sizes);
7575 SE.findArrayDimensions(Terms, Sizes, ElementSize);
75227576
75237577 if (Sizes.empty())
75247578 return nullptr;
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; Derived from the following code:
3 ;
4 ; void foo(long n, long m, long b, double A[n][m]) {
5 ; for (long i = 0; i < n; i++)
6 ; for (long j = 0; j < m; j++)
7 ; A[2i+b][2j] = 1.0;
8 ; }
9
10 ; AddRec: {{((%m * %b * sizeof(double)) + %A),+,(2 * %m * sizeof(double))}<%for.i>,+,(2 * sizeof(double))}<%for.j>
11 ; CHECK: Base offset: %A
12 ; CHECK: ArrayDecl[UnknownSize][%m] with elements of sizeof(double) bytes.
13 ; CHECK: ArrayRef[{%b,+,2}<%for.i>][{0,+,2}<%for.j>]
14
15
16 define void @foo(i64 %n, i64 %m, i64 %b, double* %A) {
17 entry:
18 br label %for.i
19
20 for.i:
21 %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
22 %outerdim = mul nsw i64 %i, 2
23 %outerdim2 = add nsw i64 %outerdim, %b
24 %tmp = mul nsw i64 %outerdim2, %m
25 br label %for.j
26
27 for.j:
28 %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
29 %prodj = mul i64 %j, 2
30 %vlaarrayidx.sum = add i64 %prodj, %tmp
31 %arrayidx = getelementptr inbounds double* %A, i64 %vlaarrayidx.sum
32 store double 1.0, double* %arrayidx
33 %j.inc = add nsw i64 %j, 1
34 %j.exitcond = icmp eq i64 %j.inc, %m
35 br i1 %j.exitcond, label %for.i.inc, label %for.j
36
37 for.i.inc:
38 %i.inc = add nsw i64 %i, 1
39 %i.exitcond = icmp eq i64 %i.inc, %n
40 br i1 %i.exitcond, label %end, label %for.i
41
42 end:
43 ret void
44 }
268268 ; CHECK: da analyze - none!
269269
270270 ; DELIN: 'Dependence Analysis' for function 'gcd4'
271 ; DELIN: da analyze - none!
272 ; DELIN: da analyze - none!
273 ; DELIN: da analyze - confused!
274 ; DELIN: da analyze - none!
271 ; DELIN: da analyze - output [* *]!
272 ; DELIN: da analyze - none!
273 ; DELIN: da analyze - confused!
274 ; DELIN: da analyze - input [* *]!
275275 ; DELIN: da analyze - confused!
276276 ; DELIN: da analyze - none!
277277
338338 ; CHECK: da analyze - none!
339339
340340 ; DELIN: 'Dependence Analysis' for function 'gcd5'
341 ; DELIN: da analyze - none!
341 ; DELIN: da analyze - output [* *]!
342342 ; DELIN: da analyze - flow [<> *]!
343343 ; DELIN: da analyze - confused!
344 ; DELIN: da analyze - none!
344 ; DELIN: da analyze - input [* *]!
345345 ; DELIN: da analyze - confused!
346346 ; DELIN: da analyze - none!
347347
409409 ; CHECK: da analyze - output [* *]!
410410
411411 ; DELIN: 'Dependence Analysis' for function 'gcd6'
412 ; DELIN: da analyze - none!
413 ; DELIN: da analyze - flow [=> =>|<]!
414 ; DELIN: da analyze - confused!
415 ; DELIN: da analyze - none!
412 ; DELIN: da analyze - output [* *]!
413 ; DELIN: da analyze - none!
414 ; DELIN: da analyze - confused!
415 ; DELIN: da analyze - input [* *]!
416416 ; DELIN: da analyze - confused!
417417 ; DELIN: da analyze - output [* *]!
418418