24
24
#include " llvm/IR/InstIterator.h"
25
25
#include " llvm/IR/Instructions.h"
26
26
#include " llvm/IR/PassManager.h"
27
+ #include " llvm/Support/CommandLine.h"
27
28
#include " llvm/Support/Debug.h"
28
29
#include " llvm/Support/raw_ostream.h"
29
30
@@ -32,6 +33,11 @@ using namespace llvm;
32
33
#define DL_NAME " delinearize"
33
34
#define DEBUG_TYPE DL_NAME
34
35
36
+ static cl::opt<bool > UseFixedSizeArrayHeuristic (
37
+ " delinearize-use-fixed-size-array-heuristic" , cl::init(false ), cl::Hidden,
38
+ cl::desc(" When printing analysis, use the heuristic for fixed-size arrays "
39
+ " if the default delinearizetion fails." ));
40
+
35
41
// Return true when S contains at least an undef value.
36
42
static inline bool containsUndefs (const SCEV *S) {
37
43
return SCEVExprContains (S, [](const SCEV *S) {
@@ -480,6 +486,184 @@ void llvm::delinearize(ScalarEvolution &SE, const SCEV *Expr,
480
486
});
481
487
}
482
488
489
+ static std::optional<APInt> tryIntoAPInt (const SCEV *S) {
490
+ if (const auto *Const = dyn_cast<SCEVConstant>(S))
491
+ return Const->getAPInt ();
492
+ return std::nullopt;
493
+ }
494
+
495
+ // / Collects the absolute values of constant steps for all induction variables.
496
+ // / Returns true if we can prove that all step recurrences are constants and \p
497
+ // / Expr is divisible by \p ElementSize. Each step recurrence is stored in \p
498
+ // / Steps after divided by \p ElementSize.
499
+ static bool collectConstantAbsSteps (ScalarEvolution &SE, const SCEV *Expr,
500
+ SmallVectorImpl<uint64_t > &Steps,
501
+ uint64_t ElementSize) {
502
+ // End of recursion. The constant value also must be a multiple of
503
+ // ElementSize.
504
+ if (const auto *Const = dyn_cast<SCEVConstant>(Expr)) {
505
+ const uint64_t Mod = Const->getAPInt ().urem (ElementSize);
506
+ return Mod == 0 ;
507
+ }
508
+
509
+ const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(Expr);
510
+ if (!AR || !AR->isAffine ())
511
+ return false ;
512
+
513
+ const SCEV *Step = AR->getStepRecurrence (SE);
514
+ std::optional<APInt> StepAPInt = tryIntoAPInt (Step);
515
+ if (!StepAPInt)
516
+ return false ;
517
+
518
+ APInt Q;
519
+ uint64_t R;
520
+ APInt::udivrem (StepAPInt->abs (), ElementSize, Q, R);
521
+ if (R != 0 )
522
+ return false ;
523
+
524
+ // Bail out when the step is too large.
525
+ std::optional<uint64_t > StepVal = Q.tryZExtValue ();
526
+ if (!StepVal)
527
+ return false ;
528
+
529
+ Steps.push_back (*StepVal);
530
+ return collectConstantAbsSteps (SE, AR->getStart (), Steps, ElementSize);
531
+ }
532
+
533
+ bool llvm::findFixedSizeArrayDimensions (ScalarEvolution &SE, const SCEV *Expr,
534
+ SmallVectorImpl<uint64_t > &Sizes,
535
+ const SCEV *ElementSize) {
536
+ if (!ElementSize)
537
+ return false ;
538
+
539
+ std::optional<APInt> ElementSizeAPInt = tryIntoAPInt (ElementSize);
540
+ if (!ElementSizeAPInt || *ElementSizeAPInt == 0 )
541
+ return false ;
542
+
543
+ std::optional<uint64_t > ElementSizeConst = ElementSizeAPInt->tryZExtValue ();
544
+
545
+ // Early exit when ElementSize is not a positive constant.
546
+ if (!ElementSizeConst)
547
+ return false ;
548
+
549
+ if (!collectConstantAbsSteps (SE, Expr, Sizes, *ElementSizeConst) ||
550
+ Sizes.empty ()) {
551
+ Sizes.clear ();
552
+ return false ;
553
+ }
554
+
555
+ // At this point, Sizes contains the absolute step recurrences for all
556
+ // induction variables. Each step recurrence must be a multiple of the size of
557
+ // the array element. Assuming that the each value represents the size of an
558
+ // array for each dimension, attempts to restore the length of each dimension
559
+ // by dividing the step recurrence by the next smaller value. For example, if
560
+ // we have the following AddRec SCEV:
561
+ //
562
+ // AddRec: {{{0,+,2048}<%for.i>,+,256}<%for.j>,+,8}<%for.k> (ElementSize=8)
563
+ //
564
+ // Then Sizes will become [256, 32, 1] after sorted. We don't know the size of
565
+ // the outermost dimension, the next dimension will be computed as 256 / 32 =
566
+ // 8, and the last dimension will be computed as 32 / 1 = 32. Thus it results
567
+ // in like Arr[UnknownSize][8][32] with elements of size 8 bytes, where Arr is
568
+ // a base pointer.
569
+ //
570
+ // TODO: Catch more cases, e.g., when a step recurrence is not divisible by
571
+ // the next smaller one, like A[i][3*j].
572
+ llvm::sort (Sizes.rbegin (), Sizes.rend ());
573
+ Sizes.erase (llvm::unique (Sizes), Sizes.end ());
574
+
575
+ // The last element in Sizes should be ElementSize. At this point, all values
576
+ // in Sizes are assumed to be divided by ElementSize, so replace it with 1.
577
+ assert (Sizes.back () != 0 && " Unexpected zero size in Sizes." );
578
+ Sizes.back () = 1 ;
579
+
580
+ for (unsigned I = 0 ; I + 1 < Sizes.size (); I++) {
581
+ uint64_t PrevSize = Sizes[I + 1 ];
582
+ if (Sizes[I] % PrevSize) {
583
+ Sizes.clear ();
584
+ return false ;
585
+ }
586
+ Sizes[I] /= PrevSize;
587
+ }
588
+
589
+ // Finally, the last element in Sizes should be ElementSize.
590
+ Sizes.back () = *ElementSizeConst;
591
+ return true ;
592
+ }
593
+
594
+ // / Splits the SCEV into two vectors of SCEVs representing the subscripts and
595
+ // / sizes of an array access, assuming that the array is a fixed size array.
596
+ // /
597
+ // / E.g., if we have the code like as follows:
598
+ // /
599
+ // / double A[42][8][32];
600
+ // / for i
601
+ // / for j
602
+ // / for k
603
+ // / use A[i][j][k]
604
+ // /
605
+ // / The access function will be represented as an AddRec SCEV like:
606
+ // /
607
+ // / AddRec: {{{0,+,2048}<%for.i>,+,256}<%for.j>,+,8}<%for.k> (ElementSize=8)
608
+ // /
609
+ // / Then findFixedSizeArrayDimensions infers the size of each dimension of the
610
+ // / array based on the fact that the value of the step recurrence is a multiple
611
+ // / of the size of the corresponding array element. In the above example, it
612
+ // / results in the following:
613
+ // /
614
+ // / CHECK: ArrayDecl[UnknownSize][8][32] with elements of 8 bytes.
615
+ // /
616
+ // / Finally each subscript will be computed as follows:
617
+ // /
618
+ // / CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
619
+ // /
620
+ // / Note that this function doesn't check the range of possible values for each
621
+ // / subscript, so the caller should perform additional boundary checks if
622
+ // / necessary.
623
+ // /
624
+ // / Also note that this function doesn't guarantee that the original array size
625
+ // / is restored "correctly". For example, in the following case:
626
+ // /
627
+ // / double A[42][4][64];
628
+ // / double B[42][8][32];
629
+ // / for i
630
+ // / for j
631
+ // / for k
632
+ // / use A[i][j][k]
633
+ // / use B[i][2*j][k]
634
+ // /
635
+ // / The access function for both accesses will be the same:
636
+ // /
637
+ // / AddRec: {{{0,+,2048}<%for.i>,+,512}<%for.j>,+,8}<%for.k> (ElementSize=8)
638
+ // /
639
+ // / The array sizes for both A and B will be computed as
640
+ // / ArrayDecl[UnknownSize][4][64], which matches for A, but not for B.
641
+ // /
642
+ // / TODO: At the moment, this function can handle only simple cases. For
643
+ // / example, we cannot handle a case where a step recurrence is not divisible
644
+ // / by the next smaller step recurrence, e.g., A[i][3*j].
645
+ bool llvm::delinearizeFixedSizeArray (ScalarEvolution &SE, const SCEV *Expr,
646
+ SmallVectorImpl<const SCEV *> &Subscripts,
647
+ SmallVectorImpl<const SCEV *> &Sizes,
648
+ const SCEV *ElementSize) {
649
+
650
+ // First step: find the fixed array size.
651
+ SmallVector<uint64_t , 4 > ConstSizes;
652
+ if (!findFixedSizeArrayDimensions (SE, Expr, ConstSizes, ElementSize)) {
653
+ Sizes.clear ();
654
+ return false ;
655
+ }
656
+
657
+ // Convert the constant size to SCEV.
658
+ for (uint64_t Size : ConstSizes)
659
+ Sizes.push_back (SE.getConstant (Expr->getType (), Size));
660
+
661
+ // Second step: compute the access functions for each subscript.
662
+ computeAccessFunctions (SE, Expr, Subscripts, Sizes);
663
+
664
+ return !Subscripts.empty ();
665
+ }
666
+
483
667
bool llvm::getIndexExpressionsFromGEP (ScalarEvolution &SE,
484
668
const GetElementPtrInst *GEP,
485
669
SmallVectorImpl<const SCEV *> &Subscripts,
@@ -586,9 +770,21 @@ void printDelinearization(raw_ostream &O, Function *F, LoopInfo *LI,
586
770
O << " AccessFunction: " << *AccessFn << " \n " ;
587
771
588
772
SmallVector<const SCEV *, 3 > Subscripts, Sizes;
773
+
774
+ auto IsDelinearizationFailed = [&]() {
775
+ return Subscripts.size () == 0 || Sizes.size () == 0 ||
776
+ Subscripts.size () != Sizes.size ();
777
+ };
778
+
589
779
delinearize (*SE, AccessFn, Subscripts, Sizes, SE->getElementSize (&Inst));
590
- if (Subscripts.size () == 0 || Sizes.size () == 0 ||
591
- Subscripts.size () != Sizes.size ()) {
780
+ if (UseFixedSizeArrayHeuristic && IsDelinearizationFailed ()) {
781
+ Subscripts.clear ();
782
+ Sizes.clear ();
783
+ delinearizeFixedSizeArray (*SE, AccessFn, Subscripts, Sizes,
784
+ SE->getElementSize (&Inst));
785
+ }
786
+
787
+ if (IsDelinearizationFailed ()) {
592
788
O << " failed to delinearize\n " ;
593
789
continue ;
594
790
}
0 commit comments