2019-07-26 04:26:34 +08:00
|
|
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
|
|
; RUN: opt < %s -div-rem-pairs -S -mtriple=powerpc64-unknown-unknown | FileCheck %s
|
|
|
|
|
|
|
|
declare void @foo(i32, i32)
|
|
|
|
|
|
|
|
define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) {
|
|
|
|
; CHECK-LABEL: @decompose_illegal_srem_same_block(
|
|
|
|
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]]
|
|
|
|
; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]]
|
|
|
|
; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
%div = sdiv i32 %a, %b
|
|
|
|
%t0 = mul i32 %div, %b
|
|
|
|
%rem = sub i32 %a, %t0
|
|
|
|
call void @foo(i32 %rem, i32 %div)
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) {
|
|
|
|
; CHECK-LABEL: @decompose_illegal_urem_same_block(
|
|
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]]
|
|
|
|
; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]]
|
|
|
|
; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]])
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
%div = udiv i32 %a, %b
|
|
|
|
%t0 = mul i32 %div, %b
|
|
|
|
%rem = sub i32 %a, %t0
|
|
|
|
call void @foo(i32 %rem, i32 %div)
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Recompose and hoist the srem if it's safe and free, otherwise keep as-is..
|
|
|
|
|
|
|
|
define i16 @hoist_srem(i16 %a, i16 %b) {
|
|
|
|
; CHECK-LABEL: @hoist_srem(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42
|
|
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
|
|
|
|
; CHECK: if:
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul i16 [[DIV]], [[B]]
|
|
|
|
; CHECK-NEXT: [[REM:%.*]] = sub i16 [[A]], [[T0]]
|
|
|
|
; CHECK-NEXT: br label [[END]]
|
|
|
|
; CHECK: end:
|
|
|
|
; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
|
|
|
|
; CHECK-NEXT: ret i16 [[RET]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%div = sdiv i16 %a, %b
|
|
|
|
%cmp = icmp eq i16 %div, 42
|
|
|
|
br i1 %cmp, label %if, label %end
|
|
|
|
|
|
|
|
if:
|
|
|
|
%t0 = mul i16 %div, %b
|
|
|
|
%rem = sub i16 %a, %t0
|
|
|
|
br label %end
|
|
|
|
|
|
|
|
end:
|
|
|
|
%ret = phi i16 [ %rem, %if ], [ 3, %entry ]
|
|
|
|
ret i16 %ret
|
|
|
|
}
|
|
|
|
|
|
|
|
; Recompose and hoist the urem if it's safe and free, otherwise keep as-is..
|
|
|
|
|
|
|
|
define i8 @hoist_urem(i8 %a, i8 %b) {
|
|
|
|
; CHECK-LABEL: @hoist_urem(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42
|
|
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
|
|
|
|
; CHECK: if:
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul i8 [[DIV]], [[B]]
|
|
|
|
; CHECK-NEXT: [[REM:%.*]] = sub i8 [[A]], [[T0]]
|
|
|
|
; CHECK-NEXT: br label [[END]]
|
|
|
|
; CHECK: end:
|
|
|
|
; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
|
|
|
|
; CHECK-NEXT: ret i8 [[RET]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%div = udiv i8 %a, %b
|
|
|
|
%cmp = icmp eq i8 %div, 42
|
|
|
|
br i1 %cmp, label %if, label %end
|
|
|
|
|
|
|
|
if:
|
|
|
|
%t0 = mul i8 %div, %b
|
|
|
|
%rem = sub i8 %a, %t0
|
|
|
|
br label %end
|
|
|
|
|
|
|
|
end:
|
|
|
|
%ret = phi i8 [ %rem, %if ], [ 3, %entry ]
|
|
|
|
ret i8 %ret
|
|
|
|
}
|
|
|
|
|
2019-07-30 23:46:03 +08:00
|
|
|
; Be careful with RAUW/invalidation if this is a srem-of-srem.
|
|
|
|
|
|
|
|
define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) {
|
|
|
|
; CHECK-LABEL: @srem_of_srem_unexpanded(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0]]
|
[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
llvm-svn: 367417
2019-07-31 20:06:38 +08:00
|
|
|
; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X]], [[TMP1]]
|
|
|
|
; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y]]
|
2019-07-30 23:46:03 +08:00
|
|
|
; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
|
[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
llvm-svn: 367417
2019-07-31 20:06:38 +08:00
|
|
|
; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y]]
|
|
|
|
; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]]
|
|
|
|
; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]]
|
2019-07-30 23:46:03 +08:00
|
|
|
;
|
|
|
|
%t0 = mul nsw i32 %Z, %Y
|
|
|
|
%t1 = sdiv i32 %X, %t0
|
|
|
|
%t2 = mul nsw i32 %t0, %t1
|
2019-07-31 20:06:16 +08:00
|
|
|
%t3 = srem i32 %X, %t0
|
|
|
|
%t4 = sdiv i32 %t3, %Y
|
2019-07-30 23:46:03 +08:00
|
|
|
%t5 = mul nsw i32 %t4, %Y
|
2019-07-31 20:06:16 +08:00
|
|
|
%t6 = srem i32 %t3, %Y
|
|
|
|
ret i32 %t6
|
2019-07-30 23:46:03 +08:00
|
|
|
}
|
|
|
|
define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) {
|
|
|
|
; CHECK-LABEL: @srem_of_srem_expanded(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]]
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]]
|
|
|
|
; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]]
|
|
|
|
; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]]
|
|
|
|
; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]]
|
|
|
|
; CHECK-NEXT: ret i32 [[T6]]
|
|
|
|
;
|
|
|
|
%t0 = mul nsw i32 %Z, %Y
|
|
|
|
%t1 = sdiv i32 %X, %t0
|
|
|
|
%t2 = mul nsw i32 %t0, %t1
|
|
|
|
%t3 = sub nsw i32 %X, %t2
|
|
|
|
%t4 = sdiv i32 %t3, %Y
|
|
|
|
%t5 = mul nsw i32 %t4, %Y
|
|
|
|
%t6 = sub nsw i32 %t3, %t5
|
|
|
|
ret i32 %t6
|
|
|
|
}
|
|
|
|
|
2019-07-26 04:26:34 +08:00
|
|
|
; If the target doesn't have a unified div/rem op for the type, keep decomposed rem
|
|
|
|
|
|
|
|
define i128 @dont_hoist_urem(i128 %a, i128 %b) {
|
|
|
|
; CHECK-LABEL: @dont_hoist_urem(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]]
|
|
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42
|
|
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]]
|
|
|
|
; CHECK: if:
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = mul i128 [[DIV]], [[B]]
|
|
|
|
; CHECK-NEXT: [[REM:%.*]] = sub i128 [[A]], [[T0]]
|
|
|
|
; CHECK-NEXT: br label [[END]]
|
|
|
|
; CHECK: end:
|
|
|
|
; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ]
|
|
|
|
; CHECK-NEXT: ret i128 [[RET]]
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%div = udiv i128 %a, %b
|
|
|
|
%cmp = icmp eq i128 %div, 42
|
|
|
|
br i1 %cmp, label %if, label %end
|
|
|
|
|
|
|
|
if:
|
|
|
|
%t0 = mul i128 %div, %b
|
|
|
|
%rem = sub i128 %a, %t0
|
|
|
|
br label %end
|
|
|
|
|
|
|
|
end:
|
|
|
|
%ret = phi i128 [ %rem, %if ], [ 3, %entry ]
|
|
|
|
ret i128 %ret
|
|
|
|
}
|