llvm.org GIT mirror llvm / 5230ad6
delinearization of arrays git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194527 91177308-0d34-0410-b5e6-96231b3b80d8 Sebastian Pop 7 years ago
20 changed file(s) with 1425 addition(s) and 3 deletion(s). Raw diff Collapse all Expand all
907907 /// based on the current constraint.
908908 void updateDirection(Dependence::DVEntry &Level,
909909 const Constraint &CurConstraint) const;
910
911 bool tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
912 SmallVectorImpl &Pair) const;
913
910914 public:
911915 static char ID; // Class identification, replacement for typeinfo
912916 DependenceAnalysis() : FunctionPass(ID) {
135135
136136 //===--------------------------------------------------------------------===//
137137 //
138 // createDelinearizationPass - This pass implements attempts to restore
139 // multidimensional array indices from linearized expressions.
140 //
141 FunctionPass *createDelinearizationPass();
142
143 //===--------------------------------------------------------------------===//
144 //
138145 // Minor pass prototypes, allowing us to expose them through bugpoint and
139146 // analyze.
140147 FunctionPass *createInstCountPass();
350350 static inline bool classof(const SCEV *S) {
351351 return S->getSCEVType() == scAddRecExpr;
352352 }
353 };
354
353
354 /// Splits the SCEV into two vectors of SCEVs representing the subscripts
355 /// and sizes of an array access. Returns the remainder of the
356 /// delinearization that is the offset start of the array.
357 const SCEV *delinearize(ScalarEvolution &SE,
358 SmallVectorImpl &Subscripts,
359 SmallVectorImpl &Sizes) const;
360 };
355361
356362 //===--------------------------------------------------------------------===//
357363 /// SCEVSMaxExpr - This class represents a signed maximum selection.
101101 void initializeDebugIRPass(PassRegistry&);
102102 void initializeDeadInstEliminationPass(PassRegistry&);
103103 void initializeDeadMachineInstructionElimPass(PassRegistry&);
104 void initializeDelinearizationPass(PassRegistry &);
104105 void initializeDependenceAnalysisPass(PassRegistry&);
105106 void initializeDomOnlyPrinterPass(PassRegistry&);
106107 void initializeDomOnlyViewerPass(PassRegistry&);
3333 initializeCFGOnlyViewerPass(Registry);
3434 initializeCFGOnlyPrinterPass(Registry);
3535 initializeDependenceAnalysisPass(Registry);
36 initializeDelinearizationPass(Registry);
3637 initializeDominanceFrontierPass(Registry);
3738 initializeDomViewerPass(Registry);
3839 initializeDomPrinterPass(Registry);
1313 CostModel.cpp
1414 CodeMetrics.cpp
1515 ConstantFolding.cpp
16 Delinearization.cpp
1617 DependenceAnalysis.cpp
1718 DomPrinter.cpp
1819 DominanceFrontier.cpp
0 //===---- Delinearization.cpp - MultiDimensional Index Delinearization ----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This implements an analysis pass that tries to delinearize all GEP
10 // instructions in all loops using the SCEV analysis functionality. This pass is
11 // only used for testing purposes: if your pass needs delinearization, please
12 // use the on-demand SCEVAddRecExpr::delinearize() function.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #define DL_NAME "delinearize"
17 #define DEBUG_TYPE DL_NAME
18 #include "llvm/IR/Constants.h"
19 #include "llvm/IR/DerivedTypes.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/Instructions.h"
22 #include "llvm/IR/LLVMContext.h"
23 #include "llvm/Pass.h"
24 #include "llvm/IR/Type.h"
25 #include "llvm/Analysis/LoopInfo.h"
26 #include "llvm/Analysis/Passes.h"
27 #include "llvm/Analysis/ScalarEvolution.h"
28 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/InstIterator.h"
32 #include "llvm/Support/raw_ostream.h"
33
34 using namespace llvm;
35
36 class Delinearization : public FunctionPass {
37 Delinearization(const Delinearization &); // do not implement
38 protected:
39 Function *F;
40 LoopInfo *LI;
41 ScalarEvolution *SE;
42
43 public:
44 static char ID; // Pass identification, replacement for typeid
45
46 Delinearization() : FunctionPass(ID) {
47 initializeDelinearizationPass(*PassRegistry::getPassRegistry());
48 }
49 virtual bool runOnFunction(Function &F);
50 virtual void getAnalysisUsage(AnalysisUsage &AU) const;
51 virtual void print(raw_ostream &O, const Module *M = 0) const;
52 };
53
54 void Delinearization::getAnalysisUsage(AnalysisUsage &AU) const {
55 AU.setPreservesAll();
56 AU.addRequired();
57 AU.addRequired();
58 }
59
60 bool Delinearization::runOnFunction(Function &F) {
61 this->F = &F;
62 SE = &getAnalysis();
63 LI = &getAnalysis();
64 return false;
65 }
66
67 static Value *getPointerOperand(Instruction &Inst) {
68 if (LoadInst *Load = dyn_cast(&Inst))
69 return Load->getPointerOperand();
70 else if (StoreInst *Store = dyn_cast(&Inst))
71 return Store->getPointerOperand();
72 else if (GetElementPtrInst *Gep = dyn_cast(&Inst))
73 return Gep->getPointerOperand();
74 return NULL;
75 }
76
77 void Delinearization::print(raw_ostream &O, const Module *) const {
78 O << "Delinearization on function " << F->getName() << ":\n";
79 for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
80 Instruction *Inst = &(*I);
81 if (!isa(Inst) && !isa(Inst) &&
82 !isa(Inst))
83 continue;
84
85 const BasicBlock *BB = Inst->getParent();
86 // Delinearize the memory access as analyzed in all the surrounding loops.
87 // Do not analyze memory accesses outside loops.
88 for (Loop *L = LI->getLoopFor(BB); L != NULL; L = L->getParentLoop()) {
89 const SCEV *AccessFn = SE->getSCEVAtScope(getPointerOperand(*Inst), L);
90 const SCEVAddRecExpr *AR = dyn_cast(AccessFn);
91 if (!AR)
92 break;
93
94 O << "AddRec: " << *AR << "\n";
95
96 SmallVector Subscripts, Sizes;
97 const SCEV *Res = AR->delinearize(*SE, Subscripts, Sizes);
98 int Size = Subscripts.size();
99 if (Res == AR || Size == 0) {
100 O << "failed to delinearize\n";
101 continue;
102 }
103 O << "Base offset: " << *Res << "\n";
104 O << "ArrayDecl[UnknownSize]";
105 for (int i = 0; i < Size - 1; i++)
106 O << "[" << *Sizes[i] << "]";
107 O << " with elements of " << *Sizes[Size - 1] << " bytes.\n";
108
109 O << "ArrayRef";
110 for (int i = 0; i < Size; i++)
111 O << "[" << *Subscripts[i] << "]";
112 O << "\n";
113 }
114 }
115 }
116
117 char Delinearization::ID = 0;
118 static const char delinearization_name[] = "Delinearization";
119 INITIALIZE_PASS_BEGIN(Delinearization, DL_NAME, delinearization_name, true,
120 true)
121 INITIALIZE_PASS_DEPENDENCY(LoopInfo)
122 INITIALIZE_PASS_END(Delinearization, DL_NAME, delinearization_name, true, true)
123
124 FunctionPass *llvm::createDelinearizationPass() { return new Delinearization; }
6060 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
6161 #include "llvm/Analysis/ValueTracking.h"
6262 #include "llvm/IR/Operator.h"
63 #include "llvm/Support/CommandLine.h"
6364 #include "llvm/Support/Debug.h"
6465 #include "llvm/Support/ErrorHandling.h"
6566 #include "llvm/Support/InstIterator.h"
102103 STATISTIC(BanerjeeApplications, "Banerjee applications");
103104 STATISTIC(BanerjeeIndependence, "Banerjee independence");
104105 STATISTIC(BanerjeeSuccesses, "Banerjee successes");
106
107 static cl::opt
108 Delinearize("da-delinearize", cl::init(false), cl::Hidden, cl::ZeroOrMore,
109 cl::desc("Try to delinearize array references."));
105110
106111 //===----------------------------------------------------------------------===//
107112 // basics
31703175 llvm_unreachable("constraint has unexpected kind");
31713176 }
31723177
3178 /// Check if we can delinearize the subscripts. If the SCEVs representing the
3179 /// source and destination array references are recurrences on a nested loop,
3180 /// this function flattens the nested recurrences into seperate recurrences
3181 /// for each loop level.
3182 bool
3183 DependenceAnalysis::tryDelinearize(const SCEV *SrcSCEV, const SCEV *DstSCEV,
3184 SmallVectorImpl &Pair) const {
3185 const SCEVAddRecExpr *SrcAR = dyn_cast(SrcSCEV);
3186 const SCEVAddRecExpr *DstAR = dyn_cast(DstSCEV);
3187 if (!SrcAR || !DstAR || !SrcAR->isAffine() || !DstAR->isAffine())
3188 return false;
3189
3190 SmallVector SrcSubscripts, DstSubscripts, SrcSizes, DstSizes;
3191 SrcAR->delinearize(*SE, SrcSubscripts, SrcSizes);
3192 DstAR->delinearize(*SE, DstSubscripts, DstSizes);
3193
3194 int size = SrcSubscripts.size();
3195 int dstSize = DstSubscripts.size();
3196 if (size != dstSize || size < 2)
3197 return false;
3198
3199 #ifndef NDEBUG
3200 DEBUG(errs() << "\nSrcSubscripts: ");
3201 for (int i = 0; i < size; i++)
3202 DEBUG(errs() << *SrcSubscripts[i]);
3203 DEBUG(errs() << "\nDstSubscripts: ");
3204 for (int i = 0; i < size; i++)
3205 DEBUG(errs() << *DstSubscripts[i]);
3206 #endif
3207
3208 Pair.resize(size);
3209 for (int i = 0; i < size; ++i) {
3210 Pair[i].Src = SrcSubscripts[i];
3211 Pair[i].Dst = DstSubscripts[i];
3212 }
3213
3214 return true;
3215 }
31733216
31743217 //===----------------------------------------------------------------------===//
31753218
32773320 DEBUG(dbgs() << " DstSCEV = " << *DstSCEV << "\n");
32783321 Pair[0].Src = SrcSCEV;
32793322 Pair[0].Dst = DstSCEV;
3323 }
3324
3325 if (Delinearize && Pairs == 1 && CommonLevels > 1 &&
3326 tryDelinearize(Pair[0].Src, Pair[0].Dst, Pair)) {
3327 DEBUG(dbgs() << " delinerized GEP\n");
3328 Pairs = Pair.size();
32803329 }
32813330
32823331 for (unsigned P = 0; P < Pairs; ++P) {
36973746 Pair[0].Dst = DstSCEV;
36983747 }
36993748
3749 if (Delinearize && Pairs == 1 && CommonLevels > 1 &&
3750 tryDelinearize(Pair[0].Src, Pair[0].Dst, Pair)) {
3751 DEBUG(dbgs() << " delinerized GEP\n");
3752 Pairs = Pair.size();
3753 }
3754
37003755 for (unsigned P = 0; P < Pairs; ++P) {
37013756 Pair[P].Loops.resize(MaxLevels + 1);
37023757 Pair[P].GroupLoops.resize(MaxLevels + 1);
66766676 return SE.getCouldNotCompute();
66776677 }
66786678
6679
6679 static const APInt gcd(const SCEVConstant *C1, const SCEVConstant *C2) {
6680 APInt A = C1->getValue()->getValue().abs();
6681 APInt B = C2->getValue()->getValue().abs();
6682 uint32_t ABW = A.getBitWidth();
6683 uint32_t BBW = B.getBitWidth();
6684
6685 if (ABW > BBW)
6686 B.zext(ABW);
6687 else if (ABW < BBW)
6688 A.zext(BBW);
6689
6690 return APIntOps::GreatestCommonDivisor(A, B);
6691 }
6692
6693 static const APInt srem(const SCEVConstant *C1, const SCEVConstant *C2) {
6694 APInt A = C1->getValue()->getValue();
6695 APInt B = C2->getValue()->getValue();
6696 uint32_t ABW = A.getBitWidth();
6697 uint32_t BBW = B.getBitWidth();
6698
6699 if (ABW > BBW)
6700 B.sext(ABW);
6701 else if (ABW < BBW)
6702 A.sext(BBW);
6703
6704 return APIntOps::srem(A, B);
6705 }
6706
6707 static const APInt sdiv(const SCEVConstant *C1, const SCEVConstant *C2) {
6708 APInt A = C1->getValue()->getValue();
6709 APInt B = C2->getValue()->getValue();
6710 uint32_t ABW = A.getBitWidth();
6711 uint32_t BBW = B.getBitWidth();
6712
6713 if (ABW > BBW)
6714 B.sext(ABW);
6715 else if (ABW < BBW)
6716 A.sext(BBW);
6717
6718 return APIntOps::sdiv(A, B);
6719 }
6720
6721 namespace {
6722 struct SCEVGCD : public SCEVVisitor {
6723 public:
6724 // Pattern match Step into Start. When Step is a multiply expression, find
6725 // the largest subexpression of Step that appears in Start. When Start is an
6726 // add expression, try to match Step in the subexpressions of Start, non
6727 // matching subexpressions are returned under Remainder.
6728 static const SCEV *findGCD(ScalarEvolution &SE, const SCEV *Start,
6729 const SCEV *Step, const SCEV **Remainder) {
6730 assert(Remainder && "Remainder should not be NULL");
6731 SCEVGCD R(SE, Step, SE.getConstant(Step->getType(), 0));
6732 const SCEV *Res = R.visit(Start);
6733 *Remainder = R.Remainder;
6734 return Res;
6735 }
6736
6737 SCEVGCD(ScalarEvolution &S, const SCEV *G, const SCEV *R)
6738 : SE(S), GCD(G), Remainder(R) {
6739 Zero = SE.getConstant(GCD->getType(), 0);
6740 One = SE.getConstant(GCD->getType(), 1);
6741 }
6742
6743 const SCEV *visitConstant(const SCEVConstant *Constant) {
6744 if (GCD == Constant || Constant == Zero)
6745 return GCD;
6746
6747 if (const SCEVConstant *CGCD = dyn_cast(GCD)) {
6748 const SCEV *Res = SE.getConstant(gcd(Constant, CGCD));
6749 if (Res != One)
6750 return Res;
6751
6752 Remainder = SE.getConstant(srem(Constant, CGCD));
6753 Constant = cast(SE.getMinusSCEV(Constant, Remainder));
6754 Res = SE.getConstant(gcd(Constant, CGCD));
6755 return Res;
6756 }
6757
6758 // When GCD is not a constant, it could be that the GCD is an Add, Mul,
6759 // AddRec, etc., in which case we want to find out how many times the
6760 // Constant divides the GCD: we then return that as the new GCD.
6761 const SCEV *Rem = Zero;
6762 const SCEV *Res = findGCD(SE, GCD, Constant, &Rem);
6763
6764 if (Res == One || Rem != Zero) {
6765 Remainder = Constant;
6766 return One;
6767 }
6768
6769 assert(isa(Res) && "Res should be a constant");
6770 Remainder = SE.getConstant(srem(Constant, cast(Res)));
6771 return Res;
6772 }
6773
6774 const SCEV *visitTruncateExpr(const SCEVTruncateExpr *Expr) {
6775 if (GCD != Expr)
6776 Remainder = Expr;
6777 return GCD;
6778 }
6779
6780 const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
6781 if (GCD != Expr)
6782 Remainder = Expr;
6783 return GCD;
6784 }
6785
6786 const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
6787 if (GCD != Expr)
6788 Remainder = Expr;
6789 return GCD;
6790 }
6791
6792 const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
6793 if (GCD == Expr)
6794 return GCD;
6795
6796 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
6797 const SCEV *Rem = Zero;
6798 const SCEV *Res = findGCD(SE, Expr->getOperand(e - 1 - i), GCD, &Rem);
6799
6800 // FIXME: There may be ambiguous situations: for instance,
6801 // GCD(-4 + (3 * %m), 2 * %m) where 2 divides -4 and %m divides (3 * %m).
6802 // The order in which the AddExpr is traversed computes a different GCD
6803 // and Remainder.
6804 if (Res != One)
6805 GCD = Res;
6806 if (Rem != Zero)
6807 Remainder = SE.getAddExpr(Remainder, Rem);
6808 }
6809
6810 return GCD;
6811 }
6812
6813 const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
6814 if (GCD == Expr)
6815 return GCD;
6816
6817 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
6818 if (Expr->getOperand(i) == GCD)
6819 return GCD;
6820 }
6821
6822 // If we have not returned yet, it means that GCD is not part of Expr.
6823 const SCEV *PartialGCD = One;
6824 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
6825 const SCEV *Rem = Zero;
6826 const SCEV *Res = findGCD(SE, Expr->getOperand(i), GCD, &Rem);
6827 if (Rem != Zero)
6828 // GCD does not divide Expr->getOperand(i).
6829 continue;
6830
6831 if (Res == GCD)
6832 return GCD;
6833 PartialGCD = SE.getMulExpr(PartialGCD, Res);
6834 if (PartialGCD == GCD)
6835 return GCD;
6836 }
6837
6838 if (PartialGCD != One)
6839 return PartialGCD;
6840
6841 Remainder = Expr;
6842 const SCEVMulExpr *Mul = dyn_cast(GCD);
6843 if (!Mul)
6844 return PartialGCD;
6845
6846 // When the GCD is a multiply expression, try to decompose it:
6847 // this occurs when Step does not divide the Start expression
6848 // as in: {(-4 + (3 * %m)),+,(2 * %m)}
6849 for (int i = 0, e = Mul->getNumOperands(); i < e; ++i) {
6850 const SCEV *Rem = Zero;
6851 const SCEV *Res = findGCD(SE, Expr, Mul->getOperand(i), &Rem);
6852 if (Rem == Zero) {
6853 Remainder = Rem;
6854 return Res;
6855 }
6856 }
6857
6858 return PartialGCD;
6859 }
6860
6861 const SCEV *visitUDivExpr(const SCEVUDivExpr *Expr) {
6862 if (GCD != Expr)
6863 Remainder = Expr;
6864 return GCD;
6865 }
6866
6867 const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
6868 if (GCD == Expr)
6869 return GCD;
6870
6871 if (!Expr->isAffine()) {
6872 Remainder = Expr;
6873 return GCD;
6874 }
6875
6876 const SCEV *Rem = Zero;
6877 const SCEV *Res = findGCD(SE, Expr->getOperand(0), GCD, &Rem);
6878 if (Rem != Zero)
6879 Remainder = SE.getAddExpr(Remainder, Rem);
6880
6881 Rem = Zero;
6882 Res = findGCD(SE, Expr->getOperand(1), Res, &Rem);
6883 if (Rem != Zero) {
6884 Remainder = Expr;
6885 return GCD;
6886 }
6887
6888 return Res;
6889 }
6890
6891 const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
6892 if (GCD != Expr)
6893 Remainder = Expr;
6894 return GCD;
6895 }
6896
6897 const SCEV *visitUMaxExpr(const SCEVUMaxExpr *Expr) {
6898 if (GCD != Expr)
6899 Remainder = Expr;
6900 return GCD;
6901 }
6902
6903 const SCEV *visitUnknown(const SCEVUnknown *Expr) {
6904 if (GCD != Expr)
6905 Remainder = Expr;
6906 return GCD;
6907 }
6908
6909 const SCEV *visitCouldNotCompute(const SCEVCouldNotCompute *Expr) {
6910 return One;
6911 }
6912
6913 private:
6914 ScalarEvolution &SE;
6915 const SCEV *GCD, *Remainder, *Zero, *One;
6916 };
6917
6918 struct SCEVDivision : public SCEVVisitor {
6919 public:
6920 // Remove from Start all multiples of Step.
6921 static const SCEV *divide(ScalarEvolution &SE, const SCEV *Start,
6922 const SCEV *Step) {
6923 SCEVDivision D(SE, Step);
6924 const SCEV *Rem = D.Zero;
6925 (void)Rem;
6926 // The division is guaranteed to succeed: Step should divide Start with no
6927 // remainder.
6928 assert(Step == SCEVGCD::findGCD(SE, Start, Step, &Rem) && Rem == D.Zero &&
6929 "Step should divide Start with no remainder.");
6930 return D.visit(Start);
6931 }
6932
6933 SCEVDivision(ScalarEvolution &S, const SCEV *G) : SE(S), GCD(G) {
6934 Zero = SE.getConstant(GCD->getType(), 0);
6935 One = SE.getConstant(GCD->getType(), 1);
6936 }
6937
6938 const SCEV *visitConstant(const SCEVConstant *Constant) {
6939 if (GCD == Constant)
6940 return One;
6941
6942 if (const SCEVConstant *CGCD = dyn_cast(GCD))
6943 return SE.getConstant(sdiv(Constant, CGCD));
6944 return Constant;
6945 }
6946
6947 const SCEV *visitTruncateExpr(const SCEVTruncateExpr *Expr) {
6948 if (GCD == Expr)
6949 return One;
6950 return Expr;
6951 }
6952
6953 const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
6954 if (GCD == Expr)
6955 return One;
6956 return Expr;
6957 }
6958
6959 const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
6960 if (GCD == Expr)
6961 return One;
6962 return Expr;
6963 }
6964
6965 const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
6966 if (GCD == Expr)
6967 return One;
6968
6969 SmallVector Operands;
6970 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
6971 Operands.push_back(divide(SE, Expr->getOperand(i), GCD));
6972
6973 if (Operands.size() == 1)
6974 return Operands[0];
6975 return SE.getAddExpr(Operands);
6976 }
6977
6978 const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
6979 if (GCD == Expr)
6980 return One;
6981
6982 bool FoundGCDTerm = false;
6983 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
6984 if (Expr->getOperand(i) == GCD)
6985 FoundGCDTerm = true;
6986
6987 SmallVector Operands;
6988 if (FoundGCDTerm) {
6989 FoundGCDTerm = false;
6990 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
6991 if (FoundGCDTerm)
6992 Operands.push_back(Expr->getOperand(i));
6993 else if (Expr->getOperand(i) == GCD)
6994 FoundGCDTerm = true;
6995 else
6996 Operands.push_back(Expr->getOperand(i));
6997 }
6998 } else {
6999 FoundGCDTerm = false;
7000 const SCEV *PartialGCD = One;
7001 for (int i = 0, e = Expr->getNumOperands(); i < e; ++i) {
7002 if (PartialGCD == GCD) {
7003 Operands.push_back(Expr->getOperand(i));
7004 continue;
7005 }
7006
7007 const SCEV *Rem = Zero;
7008 const SCEV *Res = SCEVGCD::findGCD(SE, Expr->getOperand(i), GCD, &Rem);
7009 if (Rem == Zero) {
7010 PartialGCD = SE.getMulExpr(PartialGCD, Res);
7011 Operands.push_back(divide(SE, Expr->getOperand(i), GCD));
7012 } else {
7013 Operands.push_back(Expr->getOperand(i));
7014 }
7015 }
7016 }
7017
7018 if (Operands.size() == 1)
7019 return Operands[0];
7020 return SE.getMulExpr(Operands);
7021 }
7022
7023 const SCEV *visitUDivExpr(const SCEVUDivExpr *Expr) {
7024 if (GCD == Expr)
7025 return One;
7026 return Expr;
7027 }
7028
7029 const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
7030 if (GCD == Expr)
7031 return One;
7032
7033 assert(Expr->isAffine() && "Expr should be affine");
7034
7035 const SCEV *Start = divide(SE, Expr->getStart(), GCD);
7036 const SCEV *Step = divide(SE, Expr->getStepRecurrence(SE), GCD);
7037
7038 return SE.getAddRecExpr(Start, Step, Expr->getLoop(),
7039 Expr->getNoWrapFlags());
7040 }
7041
7042 const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
7043 if (GCD == Expr)
7044 return One;
7045 return Expr;
7046 }
7047
7048 const SCEV *visitUMaxExpr(const SCEVUMaxExpr *Expr) {
7049 if (GCD == Expr)
7050 return One;
7051 return Expr;
7052 }
7053
7054 const SCEV *visitUnknown(const SCEVUnknown *Expr) {
7055 if (GCD == Expr)
7056 return One;
7057 return Expr;
7058 }
7059
7060 const SCEV *visitCouldNotCompute(const SCEVCouldNotCompute *Expr) {
7061 return Expr;
7062 }
7063
7064 private:
7065 ScalarEvolution &SE;
7066 const SCEV *GCD, *Zero, *One;
7067 };
7068 }
7069
7070 /// Splits the SCEV into two vectors of SCEVs representing the subscripts and
7071 /// sizes of an array access. Returns the remainder of the delinearization that
7072 /// is the offset start of the array. For example
7073 /// delinearize ({(((-4 + (3 * %m)))),+,(%m)}<%for.i>) {
7074 /// IV: {0,+,1}<%for.i>
7075 /// Start: -4 + (3 * %m)
7076 /// Step: %m
7077 /// SCEVUDiv (Start, Step) = 3 remainder -4
7078 /// rem = delinearize (3) = 3
7079 /// Subscripts.push_back(IV + rem)
7080 /// Sizes.push_back(Step)
7081 /// return remainder -4
7082 /// }
7083 /// When delinearize fails, it returns the SCEV unchanged.
7084 const SCEV *
7085 SCEVAddRecExpr::delinearize(ScalarEvolution &SE,
7086 SmallVectorImpl &Subscripts,
7087 SmallVectorImpl &Sizes) const {
7088 if (!this->isAffine())
7089 return this;
7090
7091 const SCEV *Start = this->getStart();
7092 const SCEV *Step = this->getStepRecurrence(SE);
7093 const SCEV *Zero = SE.getConstant(this->getType(), 0);
7094 const SCEV *One = SE.getConstant(this->getType(), 1);
7095 const SCEV *IV =
7096 SE.getAddRecExpr(Zero, One, this->getLoop(), this->getNoWrapFlags());
7097
7098 DEBUG(dbgs() << "(delinearize: " << *this << "\n");
7099
7100 if (Step == One) {
7101 DEBUG(dbgs() << "failed to delinearize " << *this << "\n)\n");
7102 return this;
7103 }
7104
7105 const SCEV *Remainder = NULL;
7106 const SCEV *GCD = SCEVGCD::findGCD(SE, Start, Step, &Remainder);
7107
7108 DEBUG(dbgs() << "GCD: " << *GCD << "\n");
7109 DEBUG(dbgs() << "Remainder: " << *Remainder << "\n");
7110
7111 if (GCD == One) {
7112 DEBUG(dbgs() << "failed to delinearize " << *this << "\n)\n");
7113 return this;
7114 }
7115
7116 const SCEV *Quotient =
7117 SCEVDivision::divide(SE, SE.getMinusSCEV(Start, Remainder), GCD);
7118 DEBUG(dbgs() << "Quotient: " << *Quotient << "\n");
7119
7120 const SCEV *Rem;
7121 if (const SCEVAddRecExpr *AR = dyn_cast(Quotient))
7122 Rem = AR->delinearize(SE, Subscripts, Sizes);
7123 else
7124 Rem = Quotient;
7125
7126 if (Step != GCD) {
7127 Step = SCEVDivision::divide(SE, Step, GCD);
7128 IV = SE.getMulExpr(IV, Step);
7129 }
7130 const SCEV *Index = SE.getAddExpr(IV, Rem);
7131
7132 Subscripts.push_back(Index);
7133 Sizes.push_back(GCD);
7134
7135 #ifndef NDEBUG
7136 int Size = Sizes.size();
7137 DEBUG(dbgs() << "succeeded to delinearize " << *this << "\n");
7138 DEBUG(dbgs() << "ArrayDecl[UnknownSize]");
7139 for (int i = 0; i < Size - 1; i++)
7140 DEBUG(dbgs() << "[" << *Sizes[i] << "]");
7141 DEBUG(dbgs() << " with elements of " << *Sizes[Size - 1] << " bytes.\n");
7142
7143 DEBUG(dbgs() << "ArrayRef");
7144 for (int i = 0; i < Size; i++)
7145 DEBUG(dbgs() << "[" << *Subscripts[i] << "]");
7146 DEBUG(dbgs() << "\n)\n");
7147 #endif
7148
7149 return Remainder;
7150 }
66807151
66817152 //===----------------------------------------------------------------------===//
66827153 // SCEVCallbackVH Class Implementation
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1 ;
2 ; void foo(long n, long m, long o, int A[n][m][o]) {
3 ; for (long i = 0; i < n; i++)
4 ; for (long j = 0; j < m; j++)
5 ; for (long k = 0; k < o; k++)
6 ; A[2*i+3][3*j-4][5*k+7] = 1;
7 ; }
8
9 ; AddRec: {{{(28 + (4 * (-4 + (3 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(12 * %o)}<%for.j>,+,20}<%for.k>
10 ; CHECK: Base offset: %A
11 ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(i32) bytes.
12 ; CHECK: ArrayRef[{3,+,2}<%for.i>][{-4,+,3}<%for.j>][{7,+,5}<%for.k>]
13
14 ; AddRec: {{(8 + ((4 + (12 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(12 * %o)}<%for.j>
15 ; CHECK: Base offset: %A
16 ; CHECK: ArrayDecl[UnknownSize][%o] with elements of sizeof(i32) bytes.
17 ; CHECK: ArrayRef[{(1 + (3 * %m)),+,(2 * %m)}<%for.i>][{2,+,(3 * %o)}<%for.j>]
18
19 ; AddRec: {(8 + ((-8 + (24 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>
20 ; CHECK: Base offset: %A
21 ; CHECK: ArrayDecl[UnknownSize] with elements of 2 bytes.
22 ; CHECK: ArrayRef[{((1 + ((-1 + (3 * %m)) * %o)) * sizeof(i32)),+,(%m * %o * sizeof(i32))}<%for.i>]
23
24 ; Function Attrs: nounwind uwtable
25 define void @foo(i64 %n, i64 %m, i64 %o, i32* nocapture %A) #0 {
26 entry:
27 %cmp32 = icmp sgt i64 %n, 0
28 br i1 %cmp32, label %for.cond1.preheader.lr.ph, label %for.end17
29
30 for.cond1.preheader.lr.ph: ; preds = %entry
31 %cmp230 = icmp sgt i64 %m, 0
32 %cmp528 = icmp sgt i64 %o, 0
33 br i1 %cmp230, label %for.i, label %for.end17
34
35 for.inc15.us: ; preds = %for.inc12.us.us, %for.i
36 %inc16.us = add nsw i64 %i.033.us, 1
37 %exitcond55 = icmp eq i64 %inc16.us, %n
38 br i1 %exitcond55, label %for.end17, label %for.i
39
40 for.i: ; preds = %for.cond1.preheader.lr.ph, %for.inc15.us
41 %i.033.us = phi i64 [ %inc16.us, %for.inc15.us ], [ 0, %for.cond1.preheader.lr.ph ]
42 %mul8.us = shl i64 %i.033.us, 1
43 %add9.us = add nsw i64 %mul8.us, 3
44 %0 = mul i64 %add9.us, %m
45 %sub.us = add i64 %0, -4
46 br i1 %cmp528, label %for.j, label %for.inc15.us
47
48 for.inc12.us.us: ; preds = %for.k
49 %inc13.us.us = add nsw i64 %j.031.us.us, 1
50 %exitcond54 = icmp eq i64 %inc13.us.us, %m
51 br i1 %exitcond54, label %for.inc15.us, label %for.j
52
53 for.j: ; preds = %for.i, %for.inc12.us.us
54 %j.031.us.us = phi i64 [ %inc13.us.us, %for.inc12.us.us ], [ 0, %for.i ]
55 %mul7.us.us = mul nsw i64 %j.031.us.us, 3
56 %tmp.us.us = add i64 %sub.us, %mul7.us.us
57 %tmp27.us.us = mul i64 %tmp.us.us, %o
58 br label %for.k
59
60 for.k: ; preds = %for.k, %for.j
61 %k.029.us.us = phi i64 [ 0, %for.j ], [ %inc.us.us, %for.k ]
62 %mul.us.us = mul nsw i64 %k.029.us.us, 5
63 %arrayidx.sum.us.us = add i64 %mul.us.us, 7
64 %arrayidx10.sum.us.us = add i64 %arrayidx.sum.us.us, %tmp27.us.us
65 %arrayidx11.us.us = getelementptr inbounds i32* %A, i64 %arrayidx10.sum.us.us
66 store i32 1, i32* %arrayidx11.us.us, align 4
67 %inc.us.us = add nsw i64 %k.029.us.us, 1
68 %exitcond = icmp eq i64 %inc.us.us, %o
69 br i1 %exitcond, label %for.inc12.us.us, label %for.k
70
71 for.end17: ; preds = %for.inc15.us, %for.cond1.preheader.lr.ph, %entry
72 ret void
73 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; #define MR(mt,n,r,c,d) mt->m[(n) * mt->mrows * mt->mcols * mt->mdeps + (r) * mt->mcols* mt->mdeps + (c) * mt->mdeps + (d)]
3 ;
4 ; struct Mat {
5 ; float* m;
6 ; int mnums;
7 ; int mrows;
8 ; int mcols;
9 ; int mdeps;
10 ; };
11 ;
12 ; typedef struct Mat Matrix;
13 ;
14 ; void jacobi(int nn, Matrix* a, Matrix* p)
15 ; {
16 ; long i, j, k, max,jmax,kmax;
17 ;
18 ; p_rows_sub = p->mrows - 1;
19 ; p_cols_sub = p->mcols - 1;
20 ; p_deps_sub = p->mdeps - 1;
21 ;
22 ; for(i = 1; i < p_rows_sub; i++)
23 ; for(j = 1; j < p_cols_sub; j++)
24 ; for(k = 1; k < p_deps_sub; k++)
25 ; MR(a,0,i,j,k) = i + j + k;
26 ; }
27
28 ; AddRec: {{{(4 + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))}<%for.j>,+,4}<%for.k>
29 ; CHECK: Base offset: %a.base
30 ; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.cols to i64)][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes.
31 ; CHECK: ArrayRef[{1,+,1}<%for.i>][{1,+,1}<%for.j>][{1,+,1}<%for.k>]
32
33 ; AddRec: {{(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))}<%for.j>
34 ; CHECK: Base offset: %a.base
35 ; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes.
36 ; CHECK: ArrayRef[{(1 + (sext i32 %a.cols to i64)),+,(sext i32 %a.cols to i64)}<%for.i>][{(-1 + (sext i32 (-1 + %p.deps) to i64)),+,(sext i32 %a.deps to i64)}<%for.j>]
37
38 ; AddRec: {(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + ((sext i32 %a.deps to i64) * (-4 + (4 * (sext i32 (-1 + %p.cols) to i64)) + (4 * (sext i32 %a.cols to i64)))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>
39 ; CHECK: Base offset: %a.base
40 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(float) bytes.
41 ; CHECK: ArrayRef[{(-1 + (sext i32 (-1 + %p.deps) to i64) + ((sext i32 %a.deps to i64) * (-1 + (sext i32 (-1 + %p.cols) to i64) + (sext i32 %a.cols to i64)))),+,((sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>]
42
43 %struct.Mat = type { float*, i32, i32, i32, i32 }
44
45 define void @jacobi(i32 %nn, %struct.Mat* nocapture %a, %struct.Mat* nocapture %p) nounwind uwtable {
46 entry:
47 %p.rows.ptr = getelementptr inbounds %struct.Mat* %p, i64 0, i32 2
48 %p.rows = load i32* %p.rows.ptr
49 %p.rows.sub = add i32 %p.rows, -1
50 %p.rows.sext = sext i32 %p.rows.sub to i64
51 %p.cols.ptr = getelementptr inbounds %struct.Mat* %p, i64 0, i32 3
52 %p.cols = load i32* %p.cols.ptr
53 %p.cols.sub = add i32 %p.cols, -1
54 %p.cols.sext = sext i32 %p.cols.sub to i64
55 %p.deps.ptr = getelementptr inbounds %struct.Mat* %p, i64 0, i32 4
56 %p.deps = load i32* %p.deps.ptr
57 %p.deps.sub = add i32 %p.deps, -1
58 %p.deps.sext = sext i32 %p.deps.sub to i64
59 %a.cols.ptr = getelementptr inbounds %struct.Mat* %a, i64 0, i32 3
60 %a.cols = load i32* %a.cols.ptr
61 %a.deps.ptr = getelementptr inbounds %struct.Mat* %a, i64 0, i32 4
62 %a.deps = load i32* %a.deps.ptr
63 %a.base.ptr = getelementptr inbounds %struct.Mat* %a, i64 0, i32 0
64 %a.base = load float** %a.base.ptr, align 8
65 br label %for.i
66
67 for.i: ; preds = %for.i.inc, %entry
68 %i = phi i64 [ %i.inc, %for.i.inc ], [ 1, %entry ]
69 br label %for.j
70
71 for.j: ; preds = %for.j.inc, %for.i
72 %j = phi i64 [ %j.inc, %for.j.inc ], [ 1, %for.i ]
73 %a.cols.sext = sext i32 %a.cols to i64
74 %a.deps.sext = sext i32 %a.deps to i64
75 br label %for.k
76
77 for.k: ; preds = %for.k, %for.j
78 %k = phi i64 [ 1, %for.j ], [ %k.inc, %for.k ]
79 %tmp1 = mul nsw i64 %a.cols.sext, %i
80 %tmp2 = add i64 %tmp1, %j
81 %tmp3 = mul i64 %tmp2, %a.deps.sext
82 %tmp4 = add nsw i64 %k, %tmp3
83 %arrayidx = getelementptr inbounds float* %a.base, i64 %tmp4
84 store float 1.000000e+00, float* %arrayidx
85 %k.inc = add nsw i64 %k, 1
86 %k.exitcond = icmp eq i64 %k.inc, %p.deps.sext
87 br i1 %k.exitcond, label %for.j.inc, label %for.k
88
89 for.j.inc: ; preds = %for.k
90 %j.inc = add nsw i64 %j, 1
91 %j.exitcond = icmp eq i64 %j.inc, %p.cols.sext
92 br i1 %j.exitcond, label %for.i.inc, label %for.j
93
94 for.i.inc: ; preds = %for.j.inc
95 %i.inc = add nsw i64 %i, 1
96 %i.exitcond = icmp eq i64 %i.inc, %p.rows.sext
97 br i1 %i.exitcond, label %end, label %for.i
98
99 end: ; preds = %for.i.inc
100 ret void
101 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; #define MR(mt,n,r,c,d) mt->m[(n) * mt->mrows * mt->mcols * mt->mdeps + (r) * mt->mcols* mt->mdeps + (c) * mt->mdeps + (d)]
3 ;
4 ; struct Mat {
5 ; float* m;
6 ; int mnums;
7 ; int mrows;
8 ; int mcols;
9 ; int mdeps;
10 ; };
11 ;
12 ; typedef struct Mat Matrix;
13 ;
14 ; void jacobi(int nn, Matrix* a, Matrix* p)
15 ; {
16 ; long i, j, k, max,jmax,kmax;
17 ;
18 ; p_rows_sub = p->mrows - 1;
19 ; p_cols_sub = p->mcols - 1;
20 ; p_deps_sub = p->mdeps - 1;
21 ;
22 ; for(i = 1; i < p_rows_sub; i++)
23 ; for(j = 1; j < p_cols_sub; j++)
24 ; for(k = 1; k < p_deps_sub; k++)
25 ; MR(a,0,i,j,k) = i + j + k;
26 ; }
27
28 ; AddRec: {{{(4 + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))}<%for.j>,+,4}<%for.k>
29 ; CHECK: Base offset: %a.base
30 ; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.cols to i64)][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes.
31 ; CHECK: ArrayRef[{1,+,1}<%for.i>][{1,+,1}<%for.j>][{1,+,1}<%for.k>]
32
33 ; AddRec: {{(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + (4 * (sext i32 %a.deps to i64) * (1 + (sext i32 %a.cols to i64))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>,+,(4 * (sext i32 %a.deps to i64))}<%for.j>
34 ; CHECK: Base offset: %a.base
35 ; CHECK: ArrayDecl[UnknownSize][(sext i32 %a.deps to i64)] with elements of sizeof(float) bytes.
36 ; CHECK: ArrayRef[{(1 + (sext i32 %a.cols to i64)),+,(sext i32 %a.cols to i64)}<%for.i>][{(-1 + (sext i32 (-1 + %p.deps) to i64)),+,(sext i32 %a.deps to i64)}<%for.j>]
37
38 ; AddRec: {(-4 + (4 * (sext i32 (-1 + %p.deps) to i64)) + ((sext i32 %a.deps to i64) * (-4 + (4 * (sext i32 (-1 + %p.cols) to i64)) + (4 * (sext i32 %a.cols to i64)))) + %a.base),+,(4 * (sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>
39 ; CHECK: Base offset: %a.base
40 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(float) bytes.
41 ; CHECK: ArrayRef[{(-1 + (sext i32 (-1 + %p.deps) to i64) + ((sext i32 %a.deps to i64) * (-1 + (sext i32 (-1 + %p.cols) to i64) + (sext i32 %a.cols to i64)))),+,((sext i32 %a.deps to i64) * (sext i32 %a.cols to i64))}<%for.i>]
42
43 %struct.Mat = type { float*, i32, i32, i32, i32 }
44
45 define void @jacobi(i32 %nn, %struct.Mat* nocapture %a, %struct.Mat* nocapture %p) nounwind uwtable {
46 entry:
47 %p.rows.ptr = getelementptr inbounds %struct.Mat* %p, i64 0, i32 2
48 %p.rows = load i32* %p.rows.ptr
49 %p.rows.sub = add i32 %p.rows, -1
50 %p.rows.sext = sext i32 %p.rows.sub to i64
51 %p.cols.ptr = getelementptr inbounds %struct.Mat* %p, i64 0, i32 3
52 %p.cols = load i32* %p.cols.ptr
53 %p.cols.sub = add i32 %p.cols, -1
54 %p.cols.sext = sext i32 %p.cols.sub to i64
55 %p.deps.ptr = getelementptr inbounds %struct.Mat* %p, i64 0, i32 4
56 %p.deps = load i32* %p.deps.ptr
57 %p.deps.sub = add i32 %p.deps, -1
58 %p.deps.sext = sext i32 %p.deps.sub to i64
59 %a.cols.ptr = getelementptr inbounds %struct.Mat* %a, i64 0, i32 3
60 %a.cols = load i32* %a.cols.ptr
61 %a.cols.sext = sext i32 %a.cols to i64
62 %a.deps.ptr = getelementptr inbounds %struct.Mat* %a, i64 0, i32 4
63 %a.deps = load i32* %a.deps.ptr
64 %a.deps.sext = sext i32 %a.deps to i64
65 %a.base.ptr = getelementptr inbounds %struct.Mat* %a, i64 0, i32 0
66 %a.base = load float** %a.base.ptr, align 8
67 br label %for.i
68
69 for.i: ; preds = %for.i.inc, %entry
70 %i = phi i64 [ %i.inc, %for.i.inc ], [ 1, %entry ]
71 br label %for.j
72
73 for.j: ; preds = %for.j.inc, %for.i
74 %j = phi i64 [ %j.inc, %for.j.inc ], [ 1, %for.i ]
75 br label %for.k
76
77 for.k: ; preds = %for.k, %for.j
78 %k = phi i64 [ 1, %for.j ], [ %k.inc, %for.k ]
79 %tmp1 = mul nsw i64 %a.cols.sext, %i
80 %tmp2 = add i64 %tmp1, %j
81 %tmp3 = mul i64 %tmp2, %a.deps.sext
82 %tmp4 = add nsw i64 %k, %tmp3
83 %arrayidx = getelementptr inbounds float* %a.base, i64 %tmp4
84 store float 1.000000e+00, float* %arrayidx
85 %k.inc = add nsw i64 %k, 1
86 %k.exitcond = icmp eq i64 %k.inc, %p.deps.sext
87 br i1 %k.exitcond, label %for.j.inc, label %for.k
88
89 for.j.inc: ; preds = %for.k
90 %j.inc = add nsw i64 %j, 1
91 %j.exitcond = icmp eq i64 %j.inc, %p.cols.sext
92 br i1 %j.exitcond, label %for.i.inc, label %for.j
93
94 for.i.inc: ; preds = %for.j.inc
95 %i.inc = add nsw i64 %i, 1
96 %i.exitcond = icmp eq i64 %i.inc, %p.rows.sext
97 br i1 %i.exitcond, label %end, label %for.i
98
99 end: ; preds = %for.i.inc
100 ret void
101 }
0 config.suffixes = ['.ll', '.c', '.cpp']
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; void foo(long n, long m, long o, double A[n][m][o]) {
3 ;
4 ; for (long i = 0; i < n; i++)
5 ; for (long j = 0; j < m; j++)
6 ; for (long k = 0; k < o; k++)
7 ; A[i+3][j-4][k+7] = 1.0;
8 ; }
9
10 ; AddRec: {{{(56 + (8 * (-4 + (3 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
11 ; CHECK: Base offset: %A
12 ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes.
13 ; CHECK: ArrayRef[{3,+,1}<%for.i>][{-4,+,1}<%for.j>][{7,+,1}<%for.k>]
14
15 ; AddRec: {{(48 + ((-24 + (24 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>
16 ; CHECK: Base offset: %A
17 ; CHECK: ArrayDecl[UnknownSize][%o] with elements of sizeof(double) bytes.
18 ; CHECK: ArrayRef[{(-3 + (3 * %m)),+,%m}<%for.i>][{6,+,%o}<%for.j>]
19
20 ; AddRec: {(48 + ((-32 + (32 * %m)) * %o) + %A),+,(8 * %m * %o)}<%for.i>
21 ; CHECK: Base offset: %A
22 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes.
23 ; CHECK: ArrayRef[{(6 + ((-4 + (4 * %m)) * %o)),+,(%m * %o)}<%for.i>]
24
25 define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
26 entry:
27 br label %for.i
28
29 for.i:
30 %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
31 br label %for.j
32
33 for.j:
34 %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
35 br label %for.k
36
37 for.k:
38 %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
39 %offset0 = add nsw i64 %i, 3
40 %subscript0 = mul i64 %offset0, %m
41 %offset1 = add nsw i64 %j, -4
42 %subscript1 = add i64 %offset1, %subscript0
43 %subscript2 = mul i64 %subscript1, %o
44 %offset2 = add nsw i64 %k, 7
45 %subscript = add i64 %subscript2, %offset2
46 %idx = getelementptr inbounds double* %A, i64 %subscript
47 store double 1.0, double* %idx
48 br label %for.k.inc
49
50 for.k.inc:
51 %k.inc = add nsw i64 %k, 1
52 %k.exitcond = icmp eq i64 %k.inc, %o
53 br i1 %k.exitcond, label %for.j.inc, label %for.k
54
55 for.j.inc:
56 %j.inc = add nsw i64 %j, 1
57 %j.exitcond = icmp eq i64 %j.inc, %m
58 br i1 %j.exitcond, label %for.i.inc, label %for.j
59
60 for.i.inc:
61 %i.inc = add nsw i64 %i, 1
62 %i.exitcond = icmp eq i64 %i.inc, %n
63 br i1 %i.exitcond, label %end, label %for.i
64
65 end:
66 ret void
67 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; void foo(long n, long m, long o, long p, double A[n][m][o+p]) {
3 ;
4 ; for (long i = 0; i < n; i++)
5 ; for (long j = 0; j < m; j++)
6 ; for (long k = 0; k < o; k++)
7 ; A[i+3][j-4][k+7] = 1.0;
8 ; }
9
10 ; AddRec: {{{(56 + (8 * (-4 + (3 * %m)) * (%o + %p)) + %A),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>,+,(8 * (%o + %p))}<%for.body6.lr.ph.us.us>,+,8}<%for.body6.us.us>
11 ; CHECK: Base offset: %A
12 ; CHECK: ArrayDecl[UnknownSize][%m][(%o + %p)] with elements of sizeof(double) bytes.
13 ; CHECK: ArrayRef[{3,+,1}<%for.cond4.preheader.lr.ph.us>][{-4,+,1}<%for.body6.lr.ph.us.us>][{7,+,1}<%for.body6.us.us>]
14
15 ; AddRec: {{(48 + (8 * %o) + (8 * (-4 + (3 * %m)) * (%o + %p)) + %A),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>,+,(8 * (%o + %p))}<%for.body6.lr.ph.us.us>
16 ; CHECK: Base offset: %A
17 ; CHECK: ArrayDecl[UnknownSize][(%o + %p)] with elements of sizeof(double) bytes.
18 ; CHECK: ArrayRef[{(-4 + (3 * %m)),+,%m}<%for.cond4.preheader.lr.ph.us>][{(6 + %o),+,(%o + %p)}<%for.body6.lr.ph.us.us>]
19
20 ; AddRec: {(48 + (8 * %o) + ((-40 + (32 * %m)) * (%o + %p)) + %A),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>
21 ; CHECK: Base offset: %A
22 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes.
23 ; CHECK: ArrayRef[{(6 + ((-5 + (4 * %m)) * (%o + %p)) + %o),+,((%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>]
24
25 define void @foo(i64 %n, i64 %m, i64 %o, i64 %p, double* nocapture %A) nounwind uwtable {
26 entry:
27 %add = add nsw i64 %p, %o
28 %cmp22 = icmp sgt i64 %n, 0
29 br i1 %cmp22, label %for.cond1.preheader.lr.ph, label %for.end16
30
31 for.cond1.preheader.lr.ph: ; preds = %entry
32 %cmp220 = icmp sgt i64 %m, 0
33 %cmp518 = icmp sgt i64 %o, 0
34 br i1 %cmp220, label %for.cond4.preheader.lr.ph.us, label %for.end16
35
36 for.inc14.us: ; preds = %for.cond4.preheader.lr.ph.us, %for.inc11.us.us
37 %inc15.us = add nsw i64 %i.023.us, 1
38 %exitcond43 = icmp eq i64 %inc15.us, %n
39 br i1 %exitcond43, label %for.end16, label %for.cond4.preheader.lr.ph.us
40
41 for.cond4.preheader.lr.ph.us: ; preds = %for.inc14.us, %for.cond1.preheader.lr.ph
42 %i.023.us = phi i64 [ %inc15.us, %for.inc14.us ], [ 0, %for.cond1.preheader.lr.ph ]
43 %add8.us = add nsw i64 %i.023.us, 3
44 %0 = mul i64 %add8.us, %m
45 %sub.us = add i64 %0, -4
46 br i1 %cmp518, label %for.body6.lr.ph.us.us, label %for.inc14.us
47
48 for.inc11.us.us: ; preds = %for.body6.us.us
49 %inc12.us.us = add nsw i64 %j.021.us.us, 1
50 %exitcond42 = icmp eq i64 %inc12.us.us, %m
51 br i1 %exitcond42, label %for.inc14.us, label %for.body6.lr.ph.us.us
52
53 for.body6.lr.ph.us.us: ; preds = %for.cond4.preheader.lr.ph.us, %for.inc11.us.us
54 %j.021.us.us = phi i64 [ %inc12.us.us, %for.inc11.us.us ], [ 0, %for.cond4.preheader.lr.ph.us ]
55 %tmp.us.us = add i64 %sub.us, %j.021.us.us
56 %tmp17.us.us = mul i64 %tmp.us.us, %add
57 br label %for.body6.us.us
58
59 for.body6.us.us: ; preds = %for.body6.us.us, %for.body6.lr.ph.us.us
60 %k.019.us.us = phi i64 [ 0, %for.body6.lr.ph.us.us ], [ %inc.us.us, %for.body6.us.us ]
61 %arrayidx.sum.us.us = add i64 %k.019.us.us, 7
62 %arrayidx9.sum.us.us = add i64 %arrayidx.sum.us.us, %tmp17.us.us
63 %arrayidx10.us.us = getelementptr inbounds double* %A, i64 %arrayidx9.sum.us.us
64 store double 1.000000e+00, double* %arrayidx10.us.us, align 8
65 %inc.us.us = add nsw i64 %k.019.us.us, 1
66 %exitcond = icmp eq i64 %inc.us.us, %o
67 br i1 %exitcond, label %for.inc11.us.us, label %for.body6.us.us
68
69 for.end16: ; preds = %for.cond1.preheader.lr.ph, %for.inc14.us, %entry
70 ret void
71 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; void foo(long n, long m, long o, double A[n][m][o], long p, long q, long r) {
3 ;
4 ; for (long i = 0; i < n; i++)
5 ; for (long j = 0; j < m; j++)
6 ; for (long k = 0; k < o; k++)
7 ; A[i+p][j+q][k+r] = 1.0;
8 ; }
9
10 ; AddRec: {{{((8 * ((((%m * %p) + %q) * %o) + %r)) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
11 ; CHECK: Base offset: %A
12 ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes.
13 ; CHECK: ArrayRef[{%p,+,1}<%for.i>][{%q,+,1}<%for.j>][{%r,+,1}<%for.k>]
14
15 ; AddRec: {{(-8 + (8 * ((((%m * %p) + %q) * %o) + %r)) + (8 * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>
16 ; CHECK: Base offset: %A
17 ; CHECK: ArrayDecl[UnknownSize][%o] with elements of sizeof(double) bytes.
18 ; CHECK: ArrayRef[{(1 + (%m * %p) + %q),+,%m}<%for.i>][{(-1 + %r),+,%o}<%for.j>]
19
20 ; AddRec: {(-8 + (8 * ((((%m * %p) + %q) * %o) + %r)) + (8 * %m * %o) + %A),+,(8 * %m * %o)}<%for.i>
21 ; CHECK: Base offset: %A
22 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes.
23 ; CHECK: ArrayRef[{(-1 + ((((1 + %p) * %m) + %q) * %o) + %r),+,(%m * %o)}<%for.i>]
24
25 define void @foo(i64 %n, i64 %m, i64 %o, double* %A, i64 %p, i64 %q, i64 %r) {
26 entry:
27 br label %for.i
28
29 for.i:
30 %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
31 br label %for.j
32
33 for.j:
34 %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
35 br label %for.k
36
37 for.k:
38 %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
39 %offset0 = add nsw i64 %i, %p
40 %subscript0 = mul i64 %offset0, %m
41 %offset1 = add nsw i64 %j, %q
42 %subscript1 = add i64 %offset1, %subscript0
43 %subscript2 = mul i64 %subscript1, %o
44 %offset2 = add nsw i64 %k, %r
45 %subscript = add i64 %subscript2, %offset2
46 %idx = getelementptr inbounds double* %A, i64 %subscript
47 store double 1.0, double* %idx
48 br label %for.k.inc
49
50 for.k.inc:
51 %k.inc = add nsw i64 %k, 1
52 %k.exitcond = icmp eq i64 %k.inc, %o
53 br i1 %k.exitcond, label %for.j.inc, label %for.k
54
55 for.j.inc:
56 %j.inc = add nsw i64 %j, 1
57 %j.exitcond = icmp eq i64 %j.inc, %m
58 br i1 %j.exitcond, label %for.i.inc, label %for.j
59
60 for.i.inc:
61 %i.inc = add nsw i64 %i, 1
62 %i.exitcond = icmp eq i64 %i.inc, %n
63 br i1 %i.exitcond, label %end, label %for.i
64
65 end:
66 ret void
67 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; Derived from the following code:
3 ;
4 ; void foo(long n, long m, double A[n][m]) {
5 ; for (long i = 0; i < n; i++)
6 ; for (long j = 0; j < m; j++)
7 ; A[i][j] = 1.0;
8 ; }
9
10 ; AddRec: {{%A,+,(8 * %m)}<%for.i>,+,8}<%for.j>
11 ; CHECK: Base offset: %A
12 ; CHECK: ArrayDecl[UnknownSize][%m] with elements of sizeof(double) bytes.
13 ; CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>]
14
15 ; AddRec: {(-8 + (8 * %m) + %A),+,(8 * %m)}<%for.i>
16 ; CHECK: Base offset: %A
17 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes.
18 ; CHECK: ArrayRef[{(-1 + %m),+,%m}<%for.i>]
19
20 define void @foo(i64 %n, i64 %m, double* %A) {
21 entry:
22 br label %for.i
23
24 for.i:
25 %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
26 %tmp = mul nsw i64 %i, %m
27 br label %for.j
28
29 for.j:
30 %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j ]
31 %vlaarrayidx.sum = add i64 %j, %tmp
32 %arrayidx = getelementptr inbounds double* %A, i64 %vlaarrayidx.sum
33 store double 1.0, double* %arrayidx
34 %j.inc = add nsw i64 %j, 1
35 %j.exitcond = icmp eq i64 %j.inc, %m
36 br i1 %j.exitcond, label %for.i.inc, label %for.j
37
38 for.i.inc:
39 %i.inc = add nsw i64 %i, 1
40 %i.exitcond = icmp eq i64 %i.inc, %n
41 br i1 %i.exitcond, label %end, label %for.i
42
43 end:
44 ret void
45 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; extern void bar(long n, long m, double A[n][m]);
3 ;
4 ; void foo(long a, long b) {
5 ; for (long n = 1; n < a; ++n)
6 ; for (long m = 1; m < b; ++m) {
7 ; double A[n][m];
8 ; for (long i = 0; i < n; i++)
9 ; for (long j = 0; j < m; j++)
10 ; A[i][j] = 1.0;
11 ; bar(n, m, A);
12 ; }
13 ; }
14
15 ; AddRec: {{%vla.us,+,{8,+,8}<%for.cond7.preheader.lr.ph.split.us.us>}<%for.body9.lr.ph.us.us>,+,8}<%for.body9.us.us>
16 ; CHECK: Base offset: %vla.us
17 ; CHECK: ArrayDecl[UnknownSize][{1,+,1}<%for.cond7.preheader.lr.ph.split.us.us>] with elements of sizeof(double) bytes.
18 ; CHECK: ArrayRef[{0,+,1}<%for.body9.lr.ph.us.us>][{0,+,1}<%for.body9.us.us>]
19
20 define void @foo(i64 %a, i64 %b) nounwind uwtable {
21 entry:
22 %cmp43 = icmp sgt i64 %a, 1
23 br i1 %cmp43, label %for.cond1.preheader.lr.ph, label %for.end19
24
25 for.cond1.preheader.lr.ph: ; preds = %entry
26 %cmp224 = icmp sgt i64 %b, 1
27 br label %for.cond1.preheader
28
29 for.cond1.preheader: ; preds = %for.inc17, %for.cond1.preheader.lr.ph
30 %indvars.iv51 = phi i64 [ 1, %for.cond1.preheader.lr.ph ], [ %indvars.iv.next52, %for.inc17 ]
31 br i1 %cmp224, label %for.cond7.preheader.lr.ph.split.us.us, label %for.inc17
32
33 for.end13.us: ; preds = %for.inc11.us.us
34 call void @bar(i64 %indvars.iv51, i64 %indvars.iv48, double* %vla.us) nounwind
35 call void @llvm.stackrestore(i8* %1)
36 %indvars.iv.next49 = add i64 %indvars.iv48, 1
37 %exitcond54 = icmp eq i64 %indvars.iv.next49, %b
38 br i1 %exitcond54, label %for.inc17, label %for.cond7.preheader.lr.ph.split.us.us
39
40 for.inc11.us.us: ; preds = %for.body9.us.us
41 %inc12.us.us = add nsw i64 %i.023.us.us, 1
42 %exitcond53 = icmp eq i64 %inc12.us.us, %indvars.iv51
43 br i1 %exitcond53, label %for.end13.us, label %for.body9.lr.ph.us.us
44
45 for.body9.lr.ph.us.us: ; preds = %for.cond7.preheader.lr.ph.split.us.us, %for.inc11.us.us
46 %i.023.us.us = phi i64 [ 0, %for.cond7.preheader.lr.ph.split.us.us ], [ %inc12.us.us, %for.inc11.us.us ]
47 %0 = mul nsw i64 %i.023.us.us, %indvars.iv48
48 br label %for.body9.us.us
49
50 for.body9.us.us: ; preds = %for.body9.us.us, %for.body9.lr.ph.us.us
51 %j.021.us.us = phi i64 [ 0, %for.body9.lr.ph.us.us ], [ %inc.us.us, %for.body9.us.us ]
52 %arrayidx.sum.us.us = add i64 %j.021.us.us, %0
53 %arrayidx10.us.us = getelementptr inbounds double* %vla.us, i64 %arrayidx.sum.us.us
54 store double 1.000000e+00, double* %arrayidx10.us.us, align 8
55 %inc.us.us = add nsw i64 %j.021.us.us, 1
56 %exitcond50 = icmp eq i64 %inc.us.us, %indvars.iv48
57 br i1 %exitcond50, label %for.inc11.us.us, label %for.body9.us.us
58
59 for.cond7.preheader.lr.ph.split.us.us: ; preds = %for.cond1.preheader, %for.end13.us
60 %indvars.iv48 = phi i64 [ %indvars.iv.next49, %for.end13.us ], [ 1, %for.cond1.preheader ]
61 %1 = call i8* @llvm.stacksave()
62 %2 = mul nuw i64 %indvars.iv48, %indvars.iv51
63 %vla.us = alloca double, i64 %2, align 16
64 br label %for.body9.lr.ph.us.us
65
66 for.inc17: ; preds = %for.end13.us, %for.cond1.preheader
67 %indvars.iv.next52 = add i64 %indvars.iv51, 1
68 %exitcond55 = icmp eq i64 %indvars.iv.next52, %a
69 br i1 %exitcond55, label %for.end19, label %for.cond1.preheader
70
71 for.end19: ; preds = %for.inc17, %entry
72 ret void
73 }
74
75 declare i8* @llvm.stacksave() nounwind
76 declare void @bar(i64, i64, double*)
77 declare void @llvm.stackrestore(i8*) nounwind
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1
2 ; void foo(long n, long m, long o, double A[n][m][o]) {
3 ;
4 ; for (long i = 0; i < n; i++)
5 ; for (long j = 0; j < m; j++)
6 ; for (long k = 0; k < o; k++)
7 ; A[i][j][k] = 1.0;
8 ; }
9
10 ; AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
11 ; CHECK: Base offset: %A
12 ; CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double) bytes.
13 ; CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
14
15 ; AddRec: {{(-8 + (8 * %o) + %A),+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>
16 ; CHECK: Base offset: %A
17 ; CHECK: ArrayDecl[UnknownSize][(%m * %o)] with elements of sizeof(double) bytes.
18 ; CHECK: ArrayRef[{0,+,1}<%for.i>][{(-1 + %o),+,%o}<%for.j>]
19
20 ; AddRec: {(-8 + (8 * %m * %o) + %A),+,(8 * %m * %o)}<%for.i>
21 ; CHECK: Base offset: %A
22 ; CHECK: ArrayDecl[UnknownSize] with elements of sizeof(double) bytes.
23 ; CHECK: ArrayRef[{(-1 + (%m * %o)),+,(%m * %o)}<%for.i>]
24
25 define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
26 entry:
27 br label %for.i
28
29 for.i:
30 %i = phi i64 [ 0, %entry ], [ %i.inc, %for.i.inc ]
31 br label %for.j
32
33 for.j:
34 %j = phi i64 [ 0, %for.i ], [ %j.inc, %for.j.inc ]
35 br label %for.k
36
37 for.k:
38 %k = phi i64 [ 0, %for.j ], [ %k.inc, %for.k.inc ]
39 %subscript0 = mul i64 %i, %m
40 %subscript1 = add i64 %j, %subscript0
41 %subscript2 = mul i64 %subscript1, %o
42 %subscript = add i64 %subscript2, %k
43 %idx = getelementptr inbounds double* %A, i64 %subscript
44 store double 1.0, double* %idx
45 br label %for.k.inc
46
47 for.k.inc:
48 %k.inc = add nsw i64 %k, 1
49 %k.exitcond = icmp eq i64 %k.inc, %o
50 br i1 %k.exitcond, label %for.j.inc, label %for.k
51
52 for.j.inc:
53 %j.inc = add nsw i64 %j, 1
54 %j.exitcond = icmp eq i64 %j.inc, %m
55 br i1 %j.exitcond, label %for.i.inc, label %for.j
56
57 for.i.inc:
58 %i.inc = add nsw i64 %i, 1
59 %i.exitcond = icmp eq i64 %i.inc, %n
60 br i1 %i.exitcond, label %end, label %for.i
61
62 end:
63 ret void
64 }
0 ; RUN: opt < %s -analyze -delinearize | FileCheck %s
1 ; void foo(int n, int m, int o, double A[n][m][o]) {
2 ;
3 ; for (int i = 0; i < n; i++)
4 ; for (int j = 0; j < m; j++)
5 ; for (int k = 0; k < o; k++)
6 ; A[i][j][k] = 1.0;
7 ; }
8
9 ; AddRec: {{{%A,+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>,+,(8 * (zext i32 %o to i64))}<%for.j>,+,8}<%for.k>
10 ; CHECK: Base offset: %A
11 ; CHECK: ArrayDecl[UnknownSize][(zext i32 %m to i64)][(zext i32 %o to i64)] with elements of 8 bytes.
12 ; CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
13
14 ; AddRec: {{((8 * (zext i32 (-1 + %o) to i64)) + %A),+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>,+,(8 * (zext i32 %o to i64))}<%for.j>
15 ; CHECK: Base offset: %A
16 ; CHECK: ArrayDecl[UnknownSize][((zext i32 %m to i64) * (zext i32 %o to i64))] with elements of 8 bytes.
17 ; CHECK: ArrayRef[{0,+,1}<%for.i>][{(zext i32 (-1 + %o) to i64),+,(zext i32 %o to i64)}<%for.j>]
18
19 ; AddRec: {((8 * (zext i32 (-1 + %o) to i64)) + (8 * (zext i32 (-1 + %m) to i64) * (zext i32 %o to i64)) + %A),+,(8 * (zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>
20 ; CHECK: Base offset: %A
21 ; CHECK: ArrayDecl[UnknownSize] with elements of 8 bytes.
22 ; CHECK: ArrayRef[{((zext i32 (-1 + %o) to i64) + ((zext i32 (-1 + %m) to i64) * (zext i32 %o to i64))),+,((zext i32 %m to i64) * (zext i32 %o to i64))}<%for.i>]
23
24 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
25 target triple = "x86_64-unknown-linux-gnu"
26
27 define void @foo(i32 %n, i32 %m, i32 %o, double* %A) {
28 entry:
29 %m_zext = zext i32 %m to i64
30 %n_zext = zext i32 %o to i64
31 br label %for.i
32
33 for.i:
34 %i = phi i64 [ %i.inc, %for.i.inc ], [ 0, %entry ]
35 br label %for.j
36
37 for.j:
38 %j = phi i64 [ %j.inc, %for.j.inc ], [ 0, %for.i ]
39 br label %for.k
40
41 for.k:
42 %k = phi i64 [ %k.inc, %for.k.inc ], [ 0, %for.j ]
43 %tmp = mul i64 %i, %m_zext
44 %tmp1 = trunc i64 %j to i32
45 %tmp2 = trunc i64 %i to i32
46 %mul.us.us = mul nsw i32 %tmp1, %tmp2
47 %tmp.us.us = add i64 %j, %tmp
48 %tmp17.us.us = mul i64 %tmp.us.us, %n_zext
49 %subscript = add i64 %tmp17.us.us, %k
50 %idx = getelementptr inbounds double* %A, i64 %subscript
51 store double 1.0, double* %idx
52 br label %for.k.inc
53
54 for.k.inc:
55 %k.inc = add i64 %k, 1
56 %k.inc.trunc = trunc i64 %k.inc to i32
57 %k.exitcond = icmp eq i32 %k.inc.trunc, %o
58 br i1 %k.exitcond, label %for.j.inc, label %for.k
59
60 for.j.inc:
61 %j.inc = add i64 %j, 1
62 %j.inc.trunc = trunc i64 %j.inc to i32
63 %j.exitcond = icmp eq i32 %j.inc.trunc, %m
64 br i1 %j.exitcond, label %for.i.inc, label %for.j
65
66 for.i.inc:
67 %i.inc = add i64 %i, 1
68 %i.inc.trunc = trunc i64 %i.inc to i32
69 %i.exitcond = icmp eq i32 %i.inc.trunc, %n
70 br i1 %i.exitcond, label %end, label %for.i
71
72 end:
73 ret void
74 }