llvm.org GIT mirror llvm / 01834db
Merging r367417: ------------------------------------------------------------------------ r367417 | lebedevri | 2019-07-31 14:06:38 +0200 (Wed, 31 Jul 2019) | 38 lines [DivRemPairs] Avoid RAUW pitfalls (PR42823) Summary: `DivRemPairs` internally creates two maps: * {sign, divident, divisor} -> div instruction * {sign, divident, divisor} -> rem instruction Then it iterates over rem map, and looks if there is an entry in div map with the same key. Then depending on some internal logic it may RAUW rem instruction with something else. But if that rem instruction is an input to other div/rem, then it was used as a key in these maps, so the old value (used in key) is now dandling, because RAUW didn't update those maps. And we can't even RAUW map keys in general, there's `ValueMap`, but we don't have a single `Value` as key... The bug was discovered via D65298, and the test there exists. Now, i'm not sure how to expose this issue in trunk. The bug is clearly there if i change the map keys to be `AssertingVH`/`PoisoningVH`, but i guess this didn't miscompiled anything thus far? I really don't think this is benin without that patch. The fix is actually rather straight-forward - instead of trying to somehow shoe-horn `ValueMap` here (doesn't fit, key isn't just `Value`), or writing a new `ValueMap` with key being a struct of `Value`s, we can just have an intermediate data structure - a vector, each entry containing matching `Div, Rem` pair, and pre-filling it before doing any modifications. This way we won't need to query map after doing RAUW, so no bug is possible. Reviewers: spatel, bogner, RKSimon, craig.topper Reviewed By: spatel Subscribers: hiraditya, hans, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D65451 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_90@367531 91177308-0d34-0410-b5e6-96231b3b80d8 Hans Wennborg 2 months ago
6 changed file(s) with 688 addition(s) and 191 deletion(s). Raw diff Collapse all Expand all
1818
1919 #include "llvm/ADT/DenseMap.h"
2020 #include "llvm/ADT/DenseMapInfo.h"
21 #include "llvm/IR/ValueHandle.h"
2122 #include
2223
2324 namespace llvm {
2728
2829 struct DivRemMapKey {
2930 bool SignedOp;
30 Value *Dividend;
31 Value *Divisor;
31 AssertingVH Dividend;
32 AssertingVH Divisor;
3233
3334 DivRemMapKey(bool InSignedOp, Value *InDividend, Value *InDivisor)
3435 : SignedOp(InSignedOp), Dividend(InDividend), Divisor(InDivisor) {}
4950 }
5051
5152 static unsigned getHashValue(const DivRemMapKey &Val) {
52 return (unsigned)(reinterpret_cast(Val.Dividend) ^
53 reinterpret_cast(Val.Divisor)) ^
53 return (unsigned)(reinterpret_cast(
54 static_cast(Val.Dividend)) ^
55 reinterpret_cast(
56 static_cast(Val.Divisor))) ^
5457 (unsigned)Val.SignedOp;
5558 }
5659 };
2222 #include "llvm/Support/DebugCounter.h"
2323 #include "llvm/Transforms/Scalar.h"
2424 #include "llvm/Transforms/Utils/BypassSlowDivision.h"
25
2526 using namespace llvm;
2627
2728 #define DEBUG_TYPE "div-rem-pairs"
3031 STATISTIC(NumDecomposed, "Number of instructions decomposed");
3132 DEBUG_COUNTER(DRPCounter, "div-rem-pairs-transform",
3233 "Controls transformations in div-rem-pairs pass");
34
35 /// A thin wrapper to store two values that we matched as div-rem pair.
36 /// We want this extra indirection to avoid dealing with RAUW'ing the map keys.
37 struct DivRemPairWorklistEntry {
38 /// The actual udiv/sdiv instruction. Source of truth.
39 AssertingVH DivInst;
40
41 /// The instruction that we have matched as a remainder instruction.
42 /// Should only be used as Value, don't introspect it.
43 AssertingVH RemInst;
44
45 DivRemPairWorklistEntry(Instruction *DivInst_, Instruction *RemInst_)
46 : DivInst(DivInst_), RemInst(RemInst_) {
47 assert((DivInst->getOpcode() == Instruction::UDiv ||
48 DivInst->getOpcode() == Instruction::SDiv) &&
49 "Not a division.");
50 assert(DivInst->getType() == RemInst->getType() && "Types should match.");
51 // We can't check anything else about remainder instruction,
52 // it's not strictly required to be a urem/srem.
53 }
54
55 /// The type for this pair, identical for both the div and rem.
56 Type *getType() const { return DivInst->getType(); }
57
58 /// Is this pair signed or unsigned?
59 bool isSigned() const { return DivInst->getOpcode() == Instruction::SDiv; }
60
61 /// In this pair, what are the divident and divisor?
62 Value *getDividend() const { return DivInst->getOperand(0); }
63 Value *getDivisor() const { return DivInst->getOperand(1); }
64 };
65 using DivRemWorklistTy = SmallVector;
66
67 /// Find matching pairs of integer div/rem ops (they have the same numerator,
68 /// denominator, and signedness). Place those pairs into a worklist for further
69 /// processing. This indirection is needed because we have to use TrackingVH<>
70 /// because we will be doing RAUW, and if one of the rem instructions we change
71 /// happens to be an input to another div/rem in the maps, we'd have problems.
72 static DivRemWorklistTy getWorklist(Function &F) {
73 // Insert all divide and remainder instructions into maps keyed by their
74 // operands and opcode (signed or unsigned).
75 DenseMap DivMap;
76 // Use a MapVector for RemMap so that instructions are moved/inserted in a
77 // deterministic order.
78 MapVector RemMap;
79 for (auto &BB : F) {
80 for (auto &I : BB) {
81 if (I.getOpcode() == Instruction::SDiv)
82 DivMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;
83 else if (I.getOpcode() == Instruction::UDiv)
84 DivMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;
85 else if (I.getOpcode() == Instruction::SRem)
86 RemMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;
87 else if (I.getOpcode() == Instruction::URem)
88 RemMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;
89 }
90 }
91
92 // We'll accumulate the matching pairs of div-rem instructions here.
93 DivRemWorklistTy Worklist;
94
95 // We can iterate over either map because we are only looking for matched
96 // pairs. Choose remainders for efficiency because they are usually even more
97 // rare than division.
98 for (auto &RemPair : RemMap) {
99 // Find the matching division instruction from the division map.
100 Instruction *DivInst = DivMap[RemPair.first];
101 if (!DivInst)
102 continue;
103
104 // We have a matching pair of div/rem instructions.
105 NumPairs++;
106 Instruction *RemInst = RemPair.second;
107
108 // Place it in the worklist.
109 Worklist.emplace_back(DivInst, RemInst);
110 }
111
112 return Worklist;
113 }
33114
34115 /// Find matching pairs of integer div/rem ops (they have the same numerator,
35116 /// denominator, and signedness). If they exist in different basic blocks, bring
49130 const DominatorTree &DT) {
50131 bool Changed = false;
51132
52 // Insert all divide and remainder instructions into maps keyed by their
53 // operands and opcode (signed or unsigned).
54 DenseMap DivMap;
55 // Use a MapVector for RemMap so that instructions are moved/inserted in a
56 // deterministic order.
57 MapVector RemMap;
58 for (auto &BB : F) {
59 for (auto &I : BB) {
60 if (I.getOpcode() == Instruction::SDiv)
61 DivMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;
62 else if (I.getOpcode() == Instruction::UDiv)
63 DivMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;
64 else if (I.getOpcode() == Instruction::SRem)
65 RemMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;
66 else if (I.getOpcode() == Instruction::URem)
67 RemMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I;
68 }
69 }
70
71 // We can iterate over either map because we are only looking for matched
72 // pairs. Choose remainders for efficiency because they are usually even more
73 // rare than division.
74 for (auto &RemPair : RemMap) {
75 // Find the matching division instruction from the division map.
76 Instruction *DivInst = DivMap[RemPair.first];
77 if (!DivInst)
78 continue;
79
80 // We have a matching pair of div/rem instructions. If one dominates the
81 // other, hoist and/or replace one.
82 NumPairs++;
83 Instruction *RemInst = RemPair.second;
84 bool IsSigned = DivInst->getOpcode() == Instruction::SDiv;
85 bool HasDivRemOp = TTI.hasDivRemOp(DivInst->getType(), IsSigned);
133 // Get the matching pairs of div-rem instructions. We want this extra
134 // indirection to avoid dealing with having to RAUW the keys of the maps.
135 DivRemWorklistTy Worklist = getWorklist(F);
136
137 // Process each entry in the worklist.
138 for (DivRemPairWorklistEntry &E : Worklist) {
139 bool HasDivRemOp = TTI.hasDivRemOp(E.getType(), E.isSigned());
140
141 auto &DivInst = E.DivInst;
142 auto &RemInst = E.RemInst;
86143
87144 // If the target supports div+rem and the instructions are in the same block
88145 // already, there's nothing to do. The backend should handle this. If the
109166 // The target does not have a single div/rem operation. Decompose the
110167 // remainder calculation as:
111168 // X % Y --> X - ((X / Y) * Y).
112 Value *X = RemInst->getOperand(0);
113 Value *Y = RemInst->getOperand(1);
169 Value *X = E.getDividend();
170 Value *Y = E.getDivisor();
114171 Instruction *Mul = BinaryOperator::CreateMul(DivInst, Y);
115172 Instruction *Sub = BinaryOperator::CreateSub(X, Mul);
116173
151208
152209 // Now kill the explicit remainder. We have replaced it with:
153210 // (sub X, (mul (div X, Y), Y)
154 RemInst->replaceAllUsesWith(Sub);
155 RemInst->eraseFromParent();
211 Sub->setName(RemInst->getName() + ".decomposed");
212 Instruction *OrigRemInst = RemInst;
213 // Update AssertingVH<> with new instruction so it doesn't assert.
214 RemInst = Sub;
215 // And replace the original instruction with the new one.
216 OrigRemInst->replaceAllUsesWith(Sub);
217 OrigRemInst->eraseFromParent();
156218 NumDecomposed++;
157219 }
158220 Changed = true;
187249 return optimizeDivRem(F, TTI, DT);
188250 }
189251 };
190 }
252 } // namespace
191253
192254 char DivRemPairsLegacyPass::ID = 0;
193255 INITIALIZE_PASS_BEGIN(DivRemPairsLegacyPass, "div-rem-pairs",
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt < %s -div-rem-pairs -S -mtriple=powerpc64-unknown-unknown | FileCheck %s
2
3 declare void @foo(i32, i32)
4
5 define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) {
6 ; CHECK-LABEL: @decompose_illegal_srem_same_block(
7 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
8 ; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]]
9 ; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]]
10 ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
11 ; CHECK-NEXT: ret void
12 ;
13 %div = sdiv i32 %a, %b
14 %t0 = mul i32 %div, %b
15 %rem = sub i32 %a, %t0
16 call void @foo(i32 %rem, i32 %div)
17 ret void
18 }
19
20 define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) {
21 ; CHECK-LABEL: @decompose_illegal_urem_same_block(
22 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]]
23 ; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]]
24 ; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]]
25 ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
26 ; CHECK-NEXT: ret void
27 ;
28 %div = udiv i32 %a, %b
29 %t0 = mul i32 %div, %b
30 %rem = sub i32 %a, %t0
31 call void @foo(i32 %rem, i32 %div)
32 ret void
33 }
34
35 ; Recompose and hoist the srem if it's safe and free, otherwise keep as-is..
36
37 define i16 @hoist_srem(i16 %a, i16 %b) {
38 ; CHECK-LABEL: @hoist_srem(
39 ; CHECK-NEXT: entry:
40 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]]
41 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42
42 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
43 ; CHECK: if:
44 ; CHECK-NEXT: [[T0:%.*]] = mul i16 [[DIV]], [[B]]
45 ; CHECK-NEXT: [[REM:%.*]] = sub i16 [[A]], [[T0]]
46 ; CHECK-NEXT: br label [[END]]
47 ; CHECK: end:
48 ; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
49 ; CHECK-NEXT: ret i16 [[RET]]
50 ;
51 entry:
52 %div = sdiv i16 %a, %b
53 %cmp = icmp eq i16 %div, 42
54 br i1 %cmp, label %if, label %end
55
56 if:
57 %t0 = mul i16 %div, %b
58 %rem = sub i16 %a, %t0
59 br label %end
60
61 end:
62 %ret = phi i16 [ %rem, %if ], [ 3, %entry ]
63 ret i16 %ret
64 }
65
66 ; Recompose and hoist the urem if it's safe and free, otherwise keep as-is..
67
68 define i8 @hoist_urem(i8 %a, i8 %b) {
69 ; CHECK-LABEL: @hoist_urem(
70 ; CHECK-NEXT: entry:
71 ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]]
72 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42
73 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
74 ; CHECK: if:
75 ; CHECK-NEXT: [[T0:%.*]] = mul i8 [[DIV]], [[B]]
76 ; CHECK-NEXT: [[REM:%.*]] = sub i8 [[A]], [[T0]]
77 ; CHECK-NEXT: br label [[END]]
78 ; CHECK: end:
79 ; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
80 ; CHECK-NEXT: ret i8 [[RET]]
81 ;
82 entry:
83 %div = udiv i8 %a, %b
84 %cmp = icmp eq i8 %div, 42
85 br i1 %cmp, label %if, label %end
86
87 if:
88 %t0 = mul i8 %div, %b
89 %rem = sub i8 %a, %t0
90 br label %end
91
92 end:
93 %ret = phi i8 [ %rem, %if ], [ 3, %entry ]
94 ret i8 %ret
95 }
96
97 ; Be careful with RAUW/invalidation if this is a srem-of-srem.
98
99 define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
100 ; CHECK-LABEL: @srem_of_srem_unexpanded(
101 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
102 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
103 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
104 ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0]]
105 ; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X]], [[TMP1]]
106 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y]]
107 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
108 ; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y]]
109 ; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]]
110 ; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]]
111 ;
112 %t0 = mul nsw i32 %Z, %Y
113 %t1 = sdiv i32 %X, %t0
114 %t2 = mul nsw i32 %t0, %t1
115 %t3 = srem i32 %X, %t0
116 %t4 = sdiv i32 %t3, %Y
117 %t5 = mul nsw i32 %t4, %Y
118 %t6 = srem i32 %t3, %Y
119 ret i32 %t6
120 }
121 define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) {
122 ; CHECK-LABEL: @srem_of_srem_expanded(
123 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
124 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
125 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
126 ; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]]
127 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
128 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
129 ; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]]
130 ; CHECK-NEXT: ret i32 [[T6]]
131 ;
132 %t0 = mul nsw i32 %Z, %Y
133 %t1 = sdiv i32 %X, %t0
134 %t2 = mul nsw i32 %t0, %t1
135 %t3 = sub nsw i32 %X, %t2
136 %t4 = sdiv i32 %t3, %Y
137 %t5 = mul nsw i32 %t4, %Y
138 %t6 = sub nsw i32 %t3, %t5
139 ret i32 %t6
140 }
141
142 ; If the target doesn't have a unified div/rem op for the type, keep decomposed rem
143
144 define i128 @dont_hoist_urem(i128 %a, i128 %b) {
145 ; CHECK-LABEL: @dont_hoist_urem(
146 ; CHECK-NEXT: entry:
147 ; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]]
148 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42
149 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
150 ; CHECK: if:
151 ; CHECK-NEXT: [[T0:%.*]] = mul i128 [[DIV]], [[B]]
152 ; CHECK-NEXT: [[REM:%.*]] = sub i128 [[A]], [[T0]]
153 ; CHECK-NEXT: br label [[END]]
154 ; CHECK: end:
155 ; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
156 ; CHECK-NEXT: ret i128 [[RET]]
157 ;
158 entry:
159 %div = udiv i128 %a, %b
160 %cmp = icmp eq i128 %div, 42
161 br i1 %cmp, label %if, label %end
162
163 if:
164 %t0 = mul i128 %div, %b
165 %rem = sub i128 %a, %t0
166 br label %end
167
168 end:
169 %ret = phi i128 [ %rem, %if ], [ 3, %entry ]
170 ret i128 %ret
171 }
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt < %s -div-rem-pairs -S -mtriple=powerpc64-unknown-unknown | FileCheck %s
12
23 declare void @foo(i32, i32)
34
45 define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) {
56 ; CHECK-LABEL: @decompose_illegal_srem_same_block(
6 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b
7 ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], %b
8 ; CHECK-NEXT: [[TMP2:%.*]] = sub i32 %a, [[TMP1]]
9 ; CHECK-NEXT: call void @foo(i32 [[TMP2]], i32 [[DIV]])
7 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
8 ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], [[B]]
9 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A]], [[TMP1]]
10 ; CHECK-NEXT: call void @foo(i32 [[REM_DECOMPOSED]], i32 [[DIV]])
1011 ; CHECK-NEXT: ret void
1112 ;
1213 %rem = srem i32 %a, %b
1718
1819 define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) {
1920 ; CHECK-LABEL: @decompose_illegal_urem_same_block(
20 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b
21 ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], %b
22 ; CHECK-NEXT: [[TMP2:%.*]] = sub i32 %a, [[TMP1]]
23 ; CHECK-NEXT: call void @foo(i32 [[TMP2]], i32 [[DIV]])
21 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]]
22 ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], [[B]]
23 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A]], [[TMP1]]
24 ; CHECK-NEXT: call void @foo(i32 [[REM_DECOMPOSED]], i32 [[DIV]])
2425 ; CHECK-NEXT: ret void
2526 ;
2627 %div = udiv i32 %a, %b
3536 define i32 @hoist_sdiv(i32 %a, i32 %b) {
3637 ; CHECK-LABEL: @hoist_sdiv(
3738 ; CHECK-NEXT: entry:
38 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b
39 ; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[DIV]], %b
40 ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 %a, [[TMP0]]
41 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 42
42 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
43 ; CHECK: if:
44 ; CHECK-NEXT: br label %end
45 ; CHECK: end:
46 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ]
39 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
40 ; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[DIV]], [[B]]
41 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A]], [[TMP0]]
42 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM_DECOMPOSED]], 42
43 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
44 ; CHECK: if:
45 ; CHECK-NEXT: br label [[END]]
46 ; CHECK: end:
47 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
4748 ; CHECK-NEXT: ret i32 [[RET]]
4849 ;
4950 entry:
6566 define i64 @hoist_udiv(i64 %a, i64 %b) {
6667 ; CHECK-LABEL: @hoist_udiv(
6768 ; CHECK-NEXT: entry:
68 ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 %a, %b
69 ; CHECK-NEXT: [[TMP0:%.*]] = mul i64 [[DIV]], %b
70 ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 %a, [[TMP0]]
71 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], 42
72 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
73 ; CHECK: if:
74 ; CHECK-NEXT: br label %end
75 ; CHECK: end:
76 ; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], %if ], [ 3, %entry ]
69 ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A:%.*]], [[B:%.*]]
70 ; CHECK-NEXT: [[TMP0:%.*]] = mul i64 [[DIV]], [[B]]
71 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i64 [[A]], [[TMP0]]
72 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[REM_DECOMPOSED]], 42
73 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
74 ; CHECK: if:
75 ; CHECK-NEXT: br label [[END]]
76 ; CHECK: end:
77 ; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
7778 ; CHECK-NEXT: ret i64 [[RET]]
7879 ;
7980 entry:
9596 define i16 @hoist_srem(i16 %a, i16 %b) {
9697 ; CHECK-LABEL: @hoist_srem(
9798 ; CHECK-NEXT: entry:
98 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 %a, %b
99 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]]
99100 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42
100 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
101 ; CHECK: if:
102 ; CHECK-NEXT: [[TMP0:%.*]] = mul i16 [[DIV]], %b
103 ; CHECK-NEXT: [[TMP1:%.*]] = sub i16 %a, [[TMP0]]
104 ; CHECK-NEXT: br label %end
105 ; CHECK: end:
106 ; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[TMP1]], %if ], [ 3, %entry ]
101 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
102 ; CHECK: if:
103 ; CHECK-NEXT: [[TMP0:%.*]] = mul i16 [[DIV]], [[B]]
104 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i16 [[A]], [[TMP0]]
105 ; CHECK-NEXT: br label [[END]]
106 ; CHECK: end:
107 ; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
107108 ; CHECK-NEXT: ret i16 [[RET]]
108109 ;
109110 entry:
125126 define i8 @hoist_urem(i8 %a, i8 %b) {
126127 ; CHECK-LABEL: @hoist_urem(
127128 ; CHECK-NEXT: entry:
128 ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 %a, %b
129 ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]]
129130 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42
130 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
131 ; CHECK: if:
132 ; CHECK-NEXT: [[TMP0:%.*]] = mul i8 [[DIV]], %b
133 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 %a, [[TMP0]]
134 ; CHECK-NEXT: br label %end
135 ; CHECK: end:
136 ; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[TMP1]], %if ], [ 3, %entry ]
131 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
132 ; CHECK: if:
133 ; CHECK-NEXT: [[TMP0:%.*]] = mul i8 [[DIV]], [[B]]
134 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i8 [[A]], [[TMP0]]
135 ; CHECK-NEXT: br label [[END]]
136 ; CHECK: end:
137 ; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
137138 ; CHECK-NEXT: ret i8 [[RET]]
138139 ;
139140 entry:
150151 ret i8 %ret
151152 }
152153
154 ; Be careful with RAUW/invalidation if this is a srem-of-srem.
155
156 define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
157 ; CHECK-LABEL: @srem_of_srem_unexpanded(
158 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
159 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
160 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
161 ; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0]]
162 ; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X]], [[TMP1]]
163 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y]]
164 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
165 ; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y]]
166 ; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]]
167 ; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]]
168 ;
169 %t0 = mul nsw i32 %Z, %Y
170 %t1 = sdiv i32 %X, %t0
171 %t2 = mul nsw i32 %t0, %t1
172 %t3 = srem i32 %X, %t0
173 %t4 = sdiv i32 %t3, %Y
174 %t5 = mul nsw i32 %t4, %Y
175 %t6 = srem i32 %t3, %Y
176 ret i32 %t6
177 }
178 define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) {
179 ; CHECK-LABEL: @srem_of_srem_expanded(
180 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
181 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
182 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
183 ; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]]
184 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
185 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
186 ; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]]
187 ; CHECK-NEXT: ret i32 [[T6]]
188 ;
189 %t0 = mul nsw i32 %Z, %Y
190 %t1 = sdiv i32 %X, %t0
191 %t2 = mul nsw i32 %t0, %t1
192 %t3 = sub nsw i32 %X, %t2
193 %t4 = sdiv i32 %t3, %Y
194 %t5 = mul nsw i32 %t4, %Y
195 %t6 = sub nsw i32 %t3, %t5
196 ret i32 %t6
197 }
198
153199 ; If the ops don't match, don't do anything: signedness.
154200
155201 define i32 @dont_hoist_udiv(i32 %a, i32 %b) {
156202 ; CHECK-LABEL: @dont_hoist_udiv(
157203 ; CHECK-NEXT: entry:
158 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
204 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
159205 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
160 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
161 ; CHECK: if:
162 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b
163 ; CHECK-NEXT: br label %end
164 ; CHECK: end:
165 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ]
206 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
207 ; CHECK: if:
208 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A]], [[B]]
209 ; CHECK-NEXT: br label [[END]]
210 ; CHECK: end:
211 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
166212 ; CHECK-NEXT: ret i32 [[RET]]
167213 ;
168214 entry:
184230 define i32 @dont_hoist_srem(i32 %a, i32 %b) {
185231 ; CHECK-LABEL: @dont_hoist_srem(
186232 ; CHECK-NEXT: entry:
187 ; CHECK-NEXT: [[REM:%.*]] = urem i32 %a, %b
233 ; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A:%.*]], [[B:%.*]]
188234 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
189 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
190 ; CHECK: if:
191 ; CHECK-NEXT: [[REM2:%.*]] = srem i32 %a, %b
192 ; CHECK-NEXT: br label %end
193 ; CHECK: end:
194 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], %if ], [ 3, %entry ]
235 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
236 ; CHECK: if:
237 ; CHECK-NEXT: [[REM2:%.*]] = srem i32 [[A]], [[B]]
238 ; CHECK-NEXT: br label [[END]]
239 ; CHECK: end:
240 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
195241 ; CHECK-NEXT: ret i32 [[RET]]
196242 ;
197243 entry:
213259 define i32 @dont_hoist_sdiv(i32 %a, i32 %b, i32 %c) {
214260 ; CHECK-LABEL: @dont_hoist_sdiv(
215261 ; CHECK-NEXT: entry:
216 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
262 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
217263 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
218 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
219 ; CHECK: if:
220 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %c
221 ; CHECK-NEXT: br label %end
222 ; CHECK: end:
223 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ]
264 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
265 ; CHECK: if:
266 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[C:%.*]]
267 ; CHECK-NEXT: br label [[END]]
268 ; CHECK: end:
269 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
224270 ; CHECK-NEXT: ret i32 [[RET]]
225271 ;
226272 entry:
242288 define i128 @dont_hoist_urem(i128 %a, i128 %b) {
243289 ; CHECK-LABEL: @dont_hoist_urem(
244290 ; CHECK-NEXT: entry:
245 ; CHECK-NEXT: [[DIV:%.*]] = udiv i128 %a, %b
291 ; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]]
246292 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42
247 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
248 ; CHECK: if:
249 ; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], %b
250 ; CHECK-NEXT: [[TMP1:%.*]] = sub i128 %a, [[TMP0]]
251 ; CHECK-NEXT: br label %end
252 ; CHECK: end:
253 ; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[TMP1]], %if ], [ 3, %entry ]
293 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
294 ; CHECK: if:
295 ; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], [[B]]
296 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i128 [[A]], [[TMP0]]
297 ; CHECK-NEXT: br label [[END]]
298 ; CHECK: end:
299 ; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
254300 ; CHECK-NEXT: ret i128 [[RET]]
255301 ;
256302 entry:
273319 define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) {
274320 ; CHECK-LABEL: @no_domination(
275321 ; CHECK-NEXT: entry:
276 ; CHECK-NEXT: br i1 %cmp, label %if, label %else
277 ; CHECK: if:
278 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b
279 ; CHECK-NEXT: br label %end
322 ; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
323 ; CHECK: if:
324 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
325 ; CHECK-NEXT: br label [[END:%.*]]
280326 ; CHECK: else:
281 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
282 ; CHECK-NEXT: br label %end
283 ; CHECK: end:
284 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ [[REM]], %else ]
327 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]]
328 ; CHECK-NEXT: br label [[END]]
329 ; CHECK: end:
330 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ]
285331 ; CHECK-NEXT: ret i32 [[RET]]
286332 ;
287333 entry:
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt < %s -div-rem-pairs -S -mtriple=x86_64-unknown-unknown | FileCheck %s
2
3 declare void @foo(i32, i32)
4
5 define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) {
6 ; CHECK-LABEL: @decompose_illegal_srem_same_block(
7 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
8 ; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]]
9 ; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]]
10 ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
11 ; CHECK-NEXT: ret void
12 ;
13 %div = sdiv i32 %a, %b
14 %t0 = mul i32 %div, %b
15 %rem = sub i32 %a, %t0
16 call void @foo(i32 %rem, i32 %div)
17 ret void
18 }
19
20 define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) {
21 ; CHECK-LABEL: @decompose_illegal_urem_same_block(
22 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]]
23 ; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]]
24 ; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]]
25 ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
26 ; CHECK-NEXT: ret void
27 ;
28 %div = udiv i32 %a, %b
29 %t0 = mul i32 %div, %b
30 %rem = sub i32 %a, %t0
31 call void @foo(i32 %rem, i32 %div)
32 ret void
33 }
34
35 ; Recompose and hoist the srem if it's safe and free, otherwise keep as-is..
36
37 define i16 @hoist_srem(i16 %a, i16 %b) {
38 ; CHECK-LABEL: @hoist_srem(
39 ; CHECK-NEXT: entry:
40 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]]
41 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42
42 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
43 ; CHECK: if:
44 ; CHECK-NEXT: [[T0:%.*]] = mul i16 [[DIV]], [[B]]
45 ; CHECK-NEXT: [[REM:%.*]] = sub i16 [[A]], [[T0]]
46 ; CHECK-NEXT: br label [[END]]
47 ; CHECK: end:
48 ; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
49 ; CHECK-NEXT: ret i16 [[RET]]
50 ;
51 entry:
52 %div = sdiv i16 %a, %b
53 %cmp = icmp eq i16 %div, 42
54 br i1 %cmp, label %if, label %end
55
56 if:
57 %t0 = mul i16 %div, %b
58 %rem = sub i16 %a, %t0
59 br label %end
60
61 end:
62 %ret = phi i16 [ %rem, %if ], [ 3, %entry ]
63 ret i16 %ret
64 }
65
66 ; Recompose and hoist the urem if it's safe and free, otherwise keep as-is..
67
68 define i8 @hoist_urem(i8 %a, i8 %b) {
69 ; CHECK-LABEL: @hoist_urem(
70 ; CHECK-NEXT: entry:
71 ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]]
72 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42
73 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
74 ; CHECK: if:
75 ; CHECK-NEXT: [[T0:%.*]] = mul i8 [[DIV]], [[B]]
76 ; CHECK-NEXT: [[REM:%.*]] = sub i8 [[A]], [[T0]]
77 ; CHECK-NEXT: br label [[END]]
78 ; CHECK: end:
79 ; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
80 ; CHECK-NEXT: ret i8 [[RET]]
81 ;
82 entry:
83 %div = udiv i8 %a, %b
84 %cmp = icmp eq i8 %div, 42
85 br i1 %cmp, label %if, label %end
86
87 if:
88 %t0 = mul i8 %div, %b
89 %rem = sub i8 %a, %t0
90 br label %end
91
92 end:
93 %ret = phi i8 [ %rem, %if ], [ 3, %entry ]
94 ret i8 %ret
95 }
96
97 ; Be careful with RAUW/invalidation if this is a srem-of-srem.
98
99 define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
100 ; CHECK-LABEL: @srem_of_srem_unexpanded(
101 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
102 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
103 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
104 ; CHECK-NEXT: [[T3:%.*]] = srem i32 [[X]], [[T0]]
105 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
106 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
107 ; CHECK-NEXT: [[T6:%.*]] = srem i32 [[T3]], [[Y]]
108 ; CHECK-NEXT: ret i32 [[T6]]
109 ;
110 %t0 = mul nsw i32 %Z, %Y
111 %t1 = sdiv i32 %X, %t0
112 %t2 = mul nsw i32 %t0, %t1
113 %t3 = srem i32 %X, %t0
114 %t4 = sdiv i32 %t3, %Y
115 %t5 = mul nsw i32 %t4, %Y
116 %t6 = srem i32 %t3, %Y
117 ret i32 %t6
118 }
119 define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) {
120 ; CHECK-LABEL: @srem_of_srem_expanded(
121 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
122 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
123 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
124 ; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]]
125 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
126 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
127 ; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]]
128 ; CHECK-NEXT: ret i32 [[T6]]
129 ;
130 %t0 = mul nsw i32 %Z, %Y
131 %t1 = sdiv i32 %X, %t0
132 %t2 = mul nsw i32 %t0, %t1
133 %t3 = sub nsw i32 %X, %t2
134 %t4 = sdiv i32 %t3, %Y
135 %t5 = mul nsw i32 %t4, %Y
136 %t6 = sub nsw i32 %t3, %t5
137 ret i32 %t6
138 }
139
140 ; If the target doesn't have a unified div/rem op for the type, keep decomposed rem
141
142 define i128 @dont_hoist_urem(i128 %a, i128 %b) {
143 ; CHECK-LABEL: @dont_hoist_urem(
144 ; CHECK-NEXT: entry:
145 ; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]]
146 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42
147 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
148 ; CHECK: if:
149 ; CHECK-NEXT: [[T0:%.*]] = mul i128 [[DIV]], [[B]]
150 ; CHECK-NEXT: [[REM:%.*]] = sub i128 [[A]], [[T0]]
151 ; CHECK-NEXT: br label [[END]]
152 ; CHECK: end:
153 ; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
154 ; CHECK-NEXT: ret i128 [[RET]]
155 ;
156 entry:
157 %div = udiv i128 %a, %b
158 %cmp = icmp eq i128 %div, 42
159 br i1 %cmp, label %if, label %end
160
161 if:
162 %t0 = mul i128 %div, %b
163 %rem = sub i128 %a, %t0
164 br label %end
165
166 end:
167 %ret = phi i128 [ %rem, %if ], [ 3, %entry ]
168 ret i128 %ret
169 }
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt < %s -div-rem-pairs -S -mtriple=x86_64-unknown-unknown | FileCheck %s
12
23 declare void @foo(i32, i32)
34
45 define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) {
56 ; CHECK-LABEL: @decompose_illegal_srem_same_block(
6 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
7 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b
7 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
8 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]]
89 ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
910 ; CHECK-NEXT: ret void
1011 ;
1617
1718 define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) {
1819 ; CHECK-LABEL: @decompose_illegal_urem_same_block(
19 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b
20 ; CHECK-NEXT: [[REM:%.*]] = urem i32 %a, %b
20 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]]
21 ; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A]], [[B]]
2122 ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
2223 ; CHECK-NEXT: ret void
2324 ;
3334 define i32 @hoist_sdiv(i32 %a, i32 %b) {
3435 ; CHECK-LABEL: @hoist_sdiv(
3536 ; CHECK-NEXT: entry:
36 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
37 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b
37 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
38 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]]
3839 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
39 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
40 ; CHECK: if:
41 ; CHECK-NEXT: br label %end
42 ; CHECK: end:
43 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ]
40 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
41 ; CHECK: if:
42 ; CHECK-NEXT: br label [[END]]
43 ; CHECK: end:
44 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
4445 ; CHECK-NEXT: ret i32 [[RET]]
4546 ;
4647 entry:
6263 define i64 @hoist_udiv(i64 %a, i64 %b) {
6364 ; CHECK-LABEL: @hoist_udiv(
6465 ; CHECK-NEXT: entry:
65 ; CHECK-NEXT: [[REM:%.*]] = urem i64 %a, %b
66 ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 %a, %b
66 ; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]]
67 ; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]]
6768 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[REM]], 42
68 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
69 ; CHECK: if:
70 ; CHECK-NEXT: br label %end
71 ; CHECK: end:
72 ; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], %if ], [ 3, %entry ]
69 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
70 ; CHECK: if:
71 ; CHECK-NEXT: br label [[END]]
72 ; CHECK: end:
73 ; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
7374 ; CHECK-NEXT: ret i64 [[RET]]
7475 ;
7576 entry:
9192 define i16 @hoist_srem(i16 %a, i16 %b) {
9293 ; CHECK-LABEL: @hoist_srem(
9394 ; CHECK-NEXT: entry:
94 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 %a, %b
95 ; CHECK-NEXT: [[REM:%.*]] = srem i16 %a, %b
95 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]]
96 ; CHECK-NEXT: [[REM:%.*]] = srem i16 [[A]], [[B]]
9697 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42
97 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
98 ; CHECK: if:
99 ; CHECK-NEXT: br label %end
100 ; CHECK: end:
101 ; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], %if ], [ 3, %entry ]
98 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
99 ; CHECK: if:
100 ; CHECK-NEXT: br label [[END]]
101 ; CHECK: end:
102 ; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
102103 ; CHECK-NEXT: ret i16 [[RET]]
103104 ;
104105 entry:
120121 define i8 @hoist_urem(i8 %a, i8 %b) {
121122 ; CHECK-LABEL: @hoist_urem(
122123 ; CHECK-NEXT: entry:
123 ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 %a, %b
124 ; CHECK-NEXT: [[REM:%.*]] = urem i8 %a, %b
124 ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]]
125 ; CHECK-NEXT: [[REM:%.*]] = urem i8 [[A]], [[B]]
125126 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42
126 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
127 ; CHECK: if:
128 ; CHECK-NEXT: br label %end
129 ; CHECK: end:
130 ; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], %if ], [ 3, %entry ]
127 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
128 ; CHECK: if:
129 ; CHECK-NEXT: br label [[END]]
130 ; CHECK: end:
131 ; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
131132 ; CHECK-NEXT: ret i8 [[RET]]
132133 ;
133134 entry:
144145 ret i8 %ret
145146 }
146147
148 ; Be careful with RAUW/invalidation if this is a srem-of-srem.
149
150 define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
151 ; CHECK-LABEL: @srem_of_srem_unexpanded(
152 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
153 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
154 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
155 ; CHECK-NEXT: [[T3:%.*]] = srem i32 [[X]], [[T0]]
156 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
157 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
158 ; CHECK-NEXT: [[T6:%.*]] = srem i32 [[T3]], [[Y]]
159 ; CHECK-NEXT: ret i32 [[T6]]
160 ;
161 %t0 = mul nsw i32 %Z, %Y
162 %t1 = sdiv i32 %X, %t0
163 %t2 = mul nsw i32 %t0, %t1
164 %t3 = srem i32 %X, %t0
165 %t4 = sdiv i32 %t3, %Y
166 %t5 = mul nsw i32 %t4, %Y
167 %t6 = srem i32 %t3, %Y
168 ret i32 %t6
169 }
170 define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) {
171 ; CHECK-LABEL: @srem_of_srem_expanded(
172 ; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
173 ; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
174 ; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
175 ; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]]
176 ; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
177 ; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
178 ; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]]
179 ; CHECK-NEXT: ret i32 [[T6]]
180 ;
181 %t0 = mul nsw i32 %Z, %Y
182 %t1 = sdiv i32 %X, %t0
183 %t2 = mul nsw i32 %t0, %t1
184 %t3 = sub nsw i32 %X, %t2
185 %t4 = sdiv i32 %t3, %Y
186 %t5 = mul nsw i32 %t4, %Y
187 %t6 = sub nsw i32 %t3, %t5
188 ret i32 %t6
189 }
190
147191 ; If the ops don't match, don't do anything: signedness.
148192
149193 define i32 @dont_hoist_udiv(i32 %a, i32 %b) {
150194 ; CHECK-LABEL: @dont_hoist_udiv(
151195 ; CHECK-NEXT: entry:
152 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
196 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
153197 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
154 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
155 ; CHECK: if:
156 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b
157 ; CHECK-NEXT: br label %end
158 ; CHECK: end:
159 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ]
198 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
199 ; CHECK: if:
200 ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A]], [[B]]
201 ; CHECK-NEXT: br label [[END]]
202 ; CHECK: end:
203 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
160204 ; CHECK-NEXT: ret i32 [[RET]]
161205 ;
162206 entry:
178222 define i32 @dont_hoist_srem(i32 %a, i32 %b) {
179223 ; CHECK-LABEL: @dont_hoist_srem(
180224 ; CHECK-NEXT: entry:
181 ; CHECK-NEXT: [[REM:%.*]] = urem i32 %a, %b
225 ; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A:%.*]], [[B:%.*]]
182226 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
183 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
184 ; CHECK: if:
185 ; CHECK-NEXT: [[REM2:%.*]] = srem i32 %a, %b
186 ; CHECK-NEXT: br label %end
187 ; CHECK: end:
188 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], %if ], [ 3, %entry ]
227 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
228 ; CHECK: if:
229 ; CHECK-NEXT: [[REM2:%.*]] = srem i32 [[A]], [[B]]
230 ; CHECK-NEXT: br label [[END]]
231 ; CHECK: end:
232 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
189233 ; CHECK-NEXT: ret i32 [[RET]]
190234 ;
191235 entry:
207251 define i32 @dont_hoist_sdiv(i32 %a, i32 %b, i32 %c) {
208252 ; CHECK-LABEL: @dont_hoist_sdiv(
209253 ; CHECK-NEXT: entry:
210 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
254 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]]
211255 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42
212 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
213 ; CHECK: if:
214 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %c
215 ; CHECK-NEXT: br label %end
216 ; CHECK: end:
217 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ]
256 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
257 ; CHECK: if:
258 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[C:%.*]]
259 ; CHECK-NEXT: br label [[END]]
260 ; CHECK: end:
261 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
218262 ; CHECK-NEXT: ret i32 [[RET]]
219263 ;
220264 entry:
236280 define i128 @dont_hoist_urem(i128 %a, i128 %b) {
237281 ; CHECK-LABEL: @dont_hoist_urem(
238282 ; CHECK-NEXT: entry:
239 ; CHECK-NEXT: [[DIV:%.*]] = udiv i128 %a, %b
283 ; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]]
240284 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42
241 ; CHECK-NEXT: br i1 [[CMP]], label %if, label %end
242 ; CHECK: if:
243 ; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], %b
244 ; CHECK-NEXT: [[TMP1:%.*]] = sub i128 %a, [[TMP0]]
245 ; CHECK-NEXT: br label %end
246 ; CHECK: end:
247 ; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[TMP1]], %if ], [ 3, %entry ]
285 ; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
286 ; CHECK: if:
287 ; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], [[B]]
288 ; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i128 [[A]], [[TMP0]]
289 ; CHECK-NEXT: br label [[END]]
290 ; CHECK: end:
291 ; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
248292 ; CHECK-NEXT: ret i128 [[RET]]
249293 ;
250294 entry:
267311 define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) {
268312 ; CHECK-LABEL: @no_domination(
269313 ; CHECK-NEXT: entry:
270 ; CHECK-NEXT: br i1 %cmp, label %if, label %else
271 ; CHECK: if:
272 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b
273 ; CHECK-NEXT: br label %end
314 ; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
315 ; CHECK: if:
316 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
317 ; CHECK-NEXT: br label [[END:%.*]]
274318 ; CHECK: else:
275 ; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b
276 ; CHECK-NEXT: br label %end
277 ; CHECK: end:
278 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ [[REM]], %else ]
319 ; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]]
320 ; CHECK-NEXT: br label [[END]]
321 ; CHECK: end:
322 ; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ]
279323 ; CHECK-NEXT: ret i32 [[RET]]
280324 ;
281325 entry: