[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / LoopUnroll / runtime-unroll-assume-no-remainder.ll
blobb7e13931d1aed70c5ede68196c0027a6f582a442
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -S -loop-unroll -unroll-runtime=true -unroll-runtime-epilog=true -unroll-count=2 | FileCheck %s
4 ; Make sure the loop is unrolled without a remainder loop based on an assumption
5 ; that the least significant bit is known to be zero.
7 define dso_local void @assumeDivisibleTC(i8* noalias nocapture %a, i8* noalias nocapture readonly %b, i32 %p, i32 %q) local_unnamed_addr {
8 ; CHECK-LABEL: @assumeDivisibleTC(
9 ; CHECK-NEXT:  entry:
10 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[P:%.*]], 1
11 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
12 ; CHECK-NEXT:    br i1 [[CMP]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
13 ; CHECK:       guarded:
14 ; CHECK-NEXT:    [[REM:%.*]] = urem i32 [[Q:%.*]], 2
15 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[REM]], 0
16 ; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP2]])
17 ; CHECK-NEXT:    [[GT:%.*]] = icmp sgt i32 [[P]], [[Q]]
18 ; CHECK-NEXT:    [[N:%.*]] = select i1 [[GT]], i32 [[P]], i32 [[Q]]
19 ; CHECK-NEXT:    [[CMP110:%.*]] = icmp sgt i32 [[N]], 0
20 ; CHECK-NEXT:    br i1 [[CMP110]], label [[FOR_BODY_PREHEADER:%.*]], label [[EXIT]]
21 ; CHECK:       for.body.preheader:
22 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
23 ; CHECK:       for.body:
24 ; CHECK-NEXT:    [[I_011:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[INC_1:%.*]], [[FOR_BODY]] ]
25 ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[B:%.*]], i32 [[I_011]]
26 ; CHECK-NEXT:    [[TMP0:%.*]] = load i8, i8* [[ARRAYIDX]], align 1
27 ; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[TMP0]], 3
28 ; CHECK-NEXT:    [[ARRAYIDX4:%.*]] = getelementptr inbounds i8, i8* [[A:%.*]], i32 [[I_011]]
29 ; CHECK-NEXT:    store i8 [[ADD]], i8* [[ARRAYIDX4]], align 1
30 ; CHECK-NEXT:    [[INC:%.*]] = add nuw nsw i32 [[I_011]], 1
31 ; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr inbounds i8, i8* [[B]], i32 [[INC]]
32 ; CHECK-NEXT:    [[TMP1:%.*]] = load i8, i8* [[ARRAYIDX_1]], align 1
33 ; CHECK-NEXT:    [[ADD_1:%.*]] = add i8 [[TMP1]], 3
34 ; CHECK-NEXT:    [[ARRAYIDX4_1:%.*]] = getelementptr inbounds i8, i8* [[A]], i32 [[INC]]
35 ; CHECK-NEXT:    store i8 [[ADD_1]], i8* [[ARRAYIDX4_1]], align 1
36 ; CHECK-NEXT:    [[INC_1]] = add nuw nsw i32 [[INC]], 1
37 ; CHECK-NEXT:    [[CMP1_1:%.*]] = icmp slt i32 [[INC_1]], [[N]]
38 ; CHECK-NEXT:    br i1 [[CMP1_1]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT:%.*]], [[LOOP0:!llvm.loop !.*]]
39 ; CHECK:       exit.loopexit:
40 ; CHECK-NEXT:    br label [[EXIT]]
41 ; CHECK:       exit:
42 ; CHECK-NEXT:    ret void
44 entry:
45   %and = and i32 %p, 1
46   %cmp = icmp eq i32 %and, 0
47   br i1 %cmp, label %guarded, label %exit
49 guarded:
50   %rem = urem i32 %q, 2
51   %cmp2 = icmp eq i32 %rem, 0
52   tail call void @llvm.assume(i1 %cmp2)
53   %gt = icmp sgt i32 %p, %q
54   %n = select i1 %gt, i32 %p, i32 %q
55   %cmp110 = icmp sgt i32 %n, 0
56   br i1 %cmp110, label %for.body, label %exit
58 for.body:
59   %i.011 = phi i32 [ %inc, %for.body ], [ 0, %guarded ]
60   %arrayidx = getelementptr inbounds i8, i8* %b, i32 %i.011
61   %0 = load i8, i8* %arrayidx, align 1
62   %add = add i8 %0, 3
63   %arrayidx4 = getelementptr inbounds i8, i8* %a, i32 %i.011
64   store i8 %add, i8* %arrayidx4, align 1
65   %inc = add nuw nsw i32 %i.011, 1
66   %cmp1 = icmp slt i32 %inc, %n
67   br i1 %cmp1, label %for.body, label %exit
69 exit:
70   ret void
73 ; Make sure the loop is unrolled with a remainder loop when the trip-count
74 ; is not provably divisible by the unroll factor.
76 define dso_local void @cannotProveDivisibleTC(i8* noalias nocapture %a, i8* noalias nocapture readonly %b, i32 %p, i32 %q) local_unnamed_addr {
77 ; CHECK-LABEL: @cannotProveDivisibleTC(
78 ; CHECK-NEXT:  entry:
79 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[P:%.*]], 6
80 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
81 ; CHECK-NEXT:    br i1 [[CMP]], label [[GUARDED:%.*]], label [[EXIT:%.*]]
82 ; CHECK:       guarded:
83 ; CHECK-NEXT:    [[REM:%.*]] = urem i32 [[Q:%.*]], 2
84 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[REM]], 0
85 ; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP2]])
86 ; CHECK-NEXT:    [[GT:%.*]] = icmp sgt i32 [[P]], [[Q]]
87 ; CHECK-NEXT:    [[N:%.*]] = select i1 [[GT]], i32 [[P]], i32 [[Q]]
88 ; CHECK-NEXT:    [[CMP110:%.*]] = icmp sgt i32 [[N]], 0
89 ; CHECK-NEXT:    br i1 [[CMP110]], label [[FOR_BODY_PREHEADER:%.*]], label [[EXIT]]
90 ; CHECK:       for.body.preheader:
91 ; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[N]], -1
92 ; CHECK-NEXT:    [[XTRAITER:%.*]] = and i32 [[N]], 1
93 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[TMP0]], 1
94 ; CHECK-NEXT:    br i1 [[TMP1]], label [[EXIT_LOOPEXIT_UNR_LCSSA:%.*]], label [[FOR_BODY_PREHEADER_NEW:%.*]]
95 ; CHECK:       for.body.preheader.new:
96 ; CHECK-NEXT:    [[UNROLL_ITER:%.*]] = sub i32 [[N]], [[XTRAITER]]
97 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
98 ; CHECK:       for.body:
99 ; CHECK-NEXT:    [[I_011:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER_NEW]] ], [ [[INC_1:%.*]], [[FOR_BODY]] ]
100 ; CHECK-NEXT:    [[NITER:%.*]] = phi i32 [ [[UNROLL_ITER]], [[FOR_BODY_PREHEADER_NEW]] ], [ [[NITER_NSUB_1:%.*]], [[FOR_BODY]] ]
101 ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8* [[B:%.*]], i32 [[I_011]]
102 ; CHECK-NEXT:    [[TMP2:%.*]] = load i8, i8* [[ARRAYIDX]], align 1
103 ; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[TMP2]], 3
104 ; CHECK-NEXT:    [[ARRAYIDX4:%.*]] = getelementptr inbounds i8, i8* [[A:%.*]], i32 [[I_011]]
105 ; CHECK-NEXT:    store i8 [[ADD]], i8* [[ARRAYIDX4]], align 1
106 ; CHECK-NEXT:    [[INC:%.*]] = add nuw nsw i32 [[I_011]], 1
107 ; CHECK-NEXT:    [[NITER_NSUB:%.*]] = sub i32 [[NITER]], 1
108 ; CHECK-NEXT:    [[ARRAYIDX_1:%.*]] = getelementptr inbounds i8, i8* [[B]], i32 [[INC]]
109 ; CHECK-NEXT:    [[TMP3:%.*]] = load i8, i8* [[ARRAYIDX_1]], align 1
110 ; CHECK-NEXT:    [[ADD_1:%.*]] = add i8 [[TMP3]], 3
111 ; CHECK-NEXT:    [[ARRAYIDX4_1:%.*]] = getelementptr inbounds i8, i8* [[A]], i32 [[INC]]
112 ; CHECK-NEXT:    store i8 [[ADD_1]], i8* [[ARRAYIDX4_1]], align 1
113 ; CHECK-NEXT:    [[INC_1]] = add nuw nsw i32 [[INC]], 1
114 ; CHECK-NEXT:    [[NITER_NSUB_1]] = sub i32 [[NITER_NSUB]], 1
115 ; CHECK-NEXT:    [[NITER_NCMP_1:%.*]] = icmp ne i32 [[NITER_NSUB_1]], 0
116 ; CHECK-NEXT:    br i1 [[NITER_NCMP_1]], label [[FOR_BODY]], label [[EXIT_LOOPEXIT_UNR_LCSSA_LOOPEXIT:%.*]], [[LOOP2:!llvm.loop !.*]]
117 ; CHECK:       exit.loopexit.unr-lcssa.loopexit:
118 ; CHECK-NEXT:    [[I_011_UNR_PH:%.*]] = phi i32 [ [[INC_1]], [[FOR_BODY]] ]
119 ; CHECK-NEXT:    br label [[EXIT_LOOPEXIT_UNR_LCSSA]]
120 ; CHECK:       exit.loopexit.unr-lcssa:
121 ; CHECK-NEXT:    [[I_011_UNR:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER]] ], [ [[I_011_UNR_PH]], [[EXIT_LOOPEXIT_UNR_LCSSA_LOOPEXIT]] ]
122 ; CHECK-NEXT:    [[LCMP_MOD:%.*]] = icmp ne i32 [[XTRAITER]], 0
123 ; CHECK-NEXT:    br i1 [[LCMP_MOD]], label [[FOR_BODY_EPIL_PREHEADER:%.*]], label [[EXIT_LOOPEXIT:%.*]]
124 ; CHECK:       for.body.epil.preheader:
125 ; CHECK-NEXT:    br label [[FOR_BODY_EPIL:%.*]]
126 ; CHECK:       for.body.epil:
127 ; CHECK-NEXT:    [[I_011_EPIL:%.*]] = phi i32 [ [[I_011_UNR]], [[FOR_BODY_EPIL_PREHEADER]] ]
128 ; CHECK-NEXT:    [[ARRAYIDX_EPIL:%.*]] = getelementptr inbounds i8, i8* [[B]], i32 [[I_011_EPIL]]
129 ; CHECK-NEXT:    [[TMP4:%.*]] = load i8, i8* [[ARRAYIDX_EPIL]], align 1
130 ; CHECK-NEXT:    [[ADD_EPIL:%.*]] = add i8 [[TMP4]], 3
131 ; CHECK-NEXT:    [[ARRAYIDX4_EPIL:%.*]] = getelementptr inbounds i8, i8* [[A]], i32 [[I_011_EPIL]]
132 ; CHECK-NEXT:    store i8 [[ADD_EPIL]], i8* [[ARRAYIDX4_EPIL]], align 1
133 ; CHECK-NEXT:    [[INC_EPIL:%.*]] = add nuw nsw i32 [[I_011_EPIL]], 1
134 ; CHECK-NEXT:    [[CMP1_EPIL:%.*]] = icmp slt i32 [[INC_EPIL]], [[N]]
135 ; CHECK-NEXT:    br label [[EXIT_LOOPEXIT_EPILOG_LCSSA:%.*]]
136 ; CHECK:       exit.loopexit.epilog-lcssa:
137 ; CHECK-NEXT:    br label [[EXIT_LOOPEXIT]]
138 ; CHECK:       exit.loopexit:
139 ; CHECK-NEXT:    br label [[EXIT]]
140 ; CHECK:       exit:
141 ; CHECK-NEXT:    ret void
143 entry:
144   %and = and i32 %p, 6
145   %cmp = icmp eq i32 %and, 0
146   br i1 %cmp, label %guarded, label %exit
148 guarded:
149   %rem = urem i32 %q, 2
150   %cmp2 = icmp eq i32 %rem, 0
151   tail call void @llvm.assume(i1 %cmp2)
152   %gt = icmp sgt i32 %p, %q
153   %n = select i1 %gt, i32 %p, i32 %q
154   %cmp110 = icmp sgt i32 %n, 0
155   br i1 %cmp110, label %for.body, label %exit
157 for.body:
158   %i.011 = phi i32 [ %inc, %for.body ], [ 0, %guarded ]
159   %arrayidx = getelementptr inbounds i8, i8* %b, i32 %i.011
160   %0 = load i8, i8* %arrayidx, align 1
161   %add = add i8 %0, 3
162   %arrayidx4 = getelementptr inbounds i8, i8* %a, i32 %i.011
163   store i8 %add, i8* %arrayidx4, align 1
164   %inc = add nuw nsw i32 %i.011, 1
165   %cmp1 = icmp slt i32 %inc, %n
166   br i1 %cmp1, label %for.body, label %exit
168 exit:
169   ret void
172 declare void @llvm.assume(i1 noundef) nofree nosync nounwind willreturn