mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
ec3b3dd170
Fix for https://bugs.llvm.org/show_bug.cgi?id=31181 and partial fix for LFTR poison handling issues in general. When LFTR moves a condition from pre-inc to post-inc, it may now depend on value that is poison due to nowrap flags. To avoid this, we clear any nowrap flag that SCEV cannot prove for the post-inc addrec. Additionally, LFTR may switch to a different IV that is dynamically dead and as such may be arbitrarily poison. This patch will correct nowrap flags in some but not all cases where this happens. This is related to the adoption of IR nowrap flags for the pre-inc addrec. (See some of the switch_to_different_iv tests, where flags are not dropped or insufficiently dropped.) Finally, there are likely similar issues with the handling of GEP inbounds, but we don't have a test case for this yet. Differential Revision: https://reviews.llvm.org/D60935 llvm-svn: 362292
361 lines
12 KiB
LLVM
361 lines
12 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -indvars -S | FileCheck %s
|
|
|
|
; PR31181: It may be necessary to drop nuw/nsw flags when moving from a
|
|
; pre-increment comparison to a post-increment comparison.
|
|
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
|
|
@a = global i32 0
|
|
|
|
define i32 @test_drop_nuw() {
|
|
; CHECK-LABEL: @test_drop_nuw(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ -2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a
|
|
; CHECK-NEXT: [[INC]] = add nsw i32 [[STOREMERGE]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 0
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%storemerge = phi i32 [ -2, %entry ], [ %inc, %loop ]
|
|
store i32 %storemerge, i32* @a
|
|
%cmp = icmp slt i32 %storemerge, -1
|
|
%inc = add nuw nsw i32 %storemerge, 1
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_drop_nsw() {
|
|
; CHECK-LABEL: @test_drop_nsw(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a
|
|
; CHECK-NEXT: [[INC]] = add nuw i32 [[STOREMERGE]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], -2147483648
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%storemerge = phi i32 [ 0, %entry ], [ %inc, %loop ]
|
|
store i32 %storemerge, i32* @a
|
|
%cmp = icmp ult i32 %storemerge, 2147483647
|
|
%inc = add nuw nsw i32 %storemerge, 1
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_no_drop_nuw() {
|
|
; CHECK-LABEL: @test_no_drop_nuw(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ -3, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], -1
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%storemerge = phi i32 [ -3, %entry ], [ %inc, %loop ]
|
|
store i32 %storemerge, i32* @a
|
|
%cmp = icmp slt i32 %storemerge, -2
|
|
%inc = add nuw nsw i32 %storemerge, 1
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
|
|
define i32 @test_no_drop_nsw() {
|
|
; CHECK-LABEL: @test_no_drop_nsw(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a
|
|
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[STOREMERGE]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 2147483647
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%storemerge = phi i32 [ 0, %entry ], [ %inc, %loop ]
|
|
store i32 %storemerge, i32* @a
|
|
%cmp = icmp ult i32 %storemerge, 2147483646
|
|
%inc = add nuw nsw i32 %storemerge, 1
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_no_add_nuw() {
|
|
; CHECK-LABEL: @test_no_add_nuw(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a
|
|
; CHECK-NEXT: [[INC]] = add nsw i32 [[STOREMERGE]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], 10
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%storemerge = phi i32 [ -1, %entry ], [ %inc, %loop ]
|
|
store i32 %storemerge, i32* @a
|
|
%cmp = icmp slt i32 %storemerge, 9
|
|
%inc = add i32 %storemerge, 1
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_drop_nsw_var_lim(i32 %lim) {
|
|
; CHECK-LABEL: @test_drop_nsw_var_lim(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[LIM:%.*]], -1
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: loop.preheader:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[LIM]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[STOREMERGE:%.*]] = phi i32 [ [[INC:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
|
|
; CHECK-NEXT: store i32 [[STOREMERGE]], i32* @a
|
|
; CHECK-NEXT: [[INC]] = add nuw i32 [[STOREMERGE]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INC]], [[TMP0]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
|
|
; CHECK: exit.loopexit:
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%c = icmp ult i32 %lim, -1
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
loop:
|
|
%storemerge = phi i32 [ 0, %entry ], [ %inc, %loop ]
|
|
store i32 %storemerge, i32* @a
|
|
%cmp = icmp ult i32 %storemerge, %lim
|
|
%inc = add nuw nsw i32 %storemerge, 1
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
; Adopted from D30446.
|
|
; We switch from %iv to %iv2 and need to change nsw to nuw in the process.
|
|
define i32 @switch_to_different_iv_post_inc(i32* %ptr, i1 %always_false) {
|
|
; CHECK-LABEL: @switch_to_different_iv_post_inc(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
|
|
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN]] ]
|
|
; CHECK-NEXT: store i32 [[IV]], i32* [[PTR:%.*]]
|
|
; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
|
|
; CHECK: never_taken:
|
|
; CHECK-NEXT: store volatile i32 [[IV2]], i32* [[PTR]]
|
|
; CHECK-NEXT: br label [[ALWAYS_TAKEN]]
|
|
; CHECK: always_taken:
|
|
; CHECK-NEXT: [[IV_INC]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[IV2_INC]] = add nuw i32 [[IV2]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483627
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond:
|
|
%iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
|
|
%iv2 = phi i32 [ 0, %entry ], [ %iv2.inc, %always_taken ]
|
|
store i32 %iv, i32* %ptr
|
|
br i1 %always_false, label %never_taken, label %always_taken
|
|
|
|
never_taken:
|
|
store volatile i32 %iv2, i32* %ptr
|
|
br label %always_taken
|
|
|
|
always_taken:
|
|
%iv.inc = add nsw i32 %iv, 1
|
|
%iv2.inc = add nuw nsw i32 %iv2, 1
|
|
%cmp = icmp slt i32 %iv, 20
|
|
br i1 %cmp, label %for.cond, label %for.end
|
|
|
|
for.end:
|
|
ret i32 0
|
|
}
|
|
|
|
; Same as previous test case, but with exit block and loop latch being distinct
|
|
; blocks requiring the use of pre-increment.
|
|
define i32 @switch_to_different_iv_pre_inc(i32* %ptr, i1 %always_false) {
|
|
; CHECK-LABEL: @switch_to_different_iv_pre_inc(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
|
|
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN]] ]
|
|
; CHECK-NEXT: store i32 [[IV]], i32* [[PTR:%.*]]
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2]], -2147483628
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
|
|
; CHECK: for.body:
|
|
; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
|
|
; CHECK: never_taken:
|
|
; CHECK-NEXT: store volatile i32 [[IV2]], i32* [[PTR]]
|
|
; CHECK-NEXT: br label [[ALWAYS_TAKEN]]
|
|
; CHECK: always_taken:
|
|
; CHECK-NEXT: [[IV_INC]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[IV2_INC]] = add nuw i32 [[IV2]], 1
|
|
; CHECK-NEXT: br label [[FOR_COND]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond:
|
|
%iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
|
|
%iv2 = phi i32 [ 0, %entry ], [ %iv2.inc, %always_taken ]
|
|
store i32 %iv, i32* %ptr
|
|
%cmp = icmp slt i32 %iv, 20
|
|
br i1 %cmp, label %for.body, label %for.end
|
|
|
|
for.body:
|
|
br i1 %always_false, label %never_taken, label %always_taken
|
|
|
|
never_taken:
|
|
store volatile i32 %iv2, i32* %ptr
|
|
br label %always_taken
|
|
|
|
always_taken:
|
|
%iv.inc = add nsw i32 %iv, 1
|
|
%iv2.inc = add nuw nsw i32 %iv2, 1
|
|
br label %for.cond
|
|
|
|
for.end:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @switch_to_different_iv_first_poison(i32* %ptr, i1 %always_false) {
|
|
; CHECK-LABEL: @switch_to_different_iv_first_poison(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN]] ]
|
|
; CHECK-NEXT: store i32 [[IV]], i32* [[PTR:%.*]]
|
|
; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
|
|
; CHECK: never_taken:
|
|
; CHECK-NEXT: store volatile i32 [[IV2]], i32* [[PTR]]
|
|
; CHECK-NEXT: br label [[ALWAYS_TAKEN]]
|
|
; CHECK: always_taken:
|
|
; CHECK-NEXT: [[IV2_INC]] = add nuw nsw i32 [[IV2]], 1
|
|
; CHECK-NEXT: [[IV_INC]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483628
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond:
|
|
%iv2 = phi i32 [ -1, %entry ], [ %iv2.inc, %always_taken ]
|
|
%iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
|
|
store i32 %iv, i32* %ptr
|
|
br i1 %always_false, label %never_taken, label %always_taken
|
|
|
|
never_taken:
|
|
store volatile i32 %iv2, i32* %ptr
|
|
br label %always_taken
|
|
|
|
always_taken:
|
|
%iv2.inc = add nuw nsw i32 %iv2, 1
|
|
%iv.inc = add nsw i32 %iv, 1
|
|
%cmp = icmp slt i32 %iv, 20
|
|
br i1 %cmp, label %for.cond, label %for.end
|
|
|
|
for.end:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @switch_to_different_iv_second_poison(i32* %ptr, i1 %always_false) {
|
|
; CHECK-LABEL: @switch_to_different_iv_second_poison(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_COND:%.*]]
|
|
; CHECK: for.cond:
|
|
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ -2, [[ENTRY:%.*]] ], [ [[IV2_INC:%.*]], [[ALWAYS_TAKEN:%.*]] ]
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ -2147483648, [[ENTRY]] ], [ [[IV_INC:%.*]], [[ALWAYS_TAKEN]] ]
|
|
; CHECK-NEXT: store i32 [[IV]], i32* [[PTR:%.*]]
|
|
; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_TAKEN:%.*]], label [[ALWAYS_TAKEN]]
|
|
; CHECK: never_taken:
|
|
; CHECK-NEXT: store volatile i32 [[IV2]], i32* [[PTR]]
|
|
; CHECK-NEXT: br label [[ALWAYS_TAKEN]]
|
|
; CHECK: always_taken:
|
|
; CHECK-NEXT: [[IV2_INC]] = add nsw i32 [[IV2]], 1
|
|
; CHECK-NEXT: [[IV_INC]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2_INC]], -2147483629
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND]], label [[FOR_END:%.*]]
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond:
|
|
%iv2 = phi i32 [ -2, %entry ], [ %iv2.inc, %always_taken ]
|
|
%iv = phi i32 [ -2147483648, %entry ], [ %iv.inc, %always_taken ]
|
|
store i32 %iv, i32* %ptr
|
|
br i1 %always_false, label %never_taken, label %always_taken
|
|
|
|
never_taken:
|
|
store volatile i32 %iv2, i32* %ptr
|
|
br label %always_taken
|
|
|
|
always_taken:
|
|
%iv2.inc = add nuw nsw i32 %iv2, 1
|
|
%iv.inc = add nsw i32 %iv, 1
|
|
%cmp = icmp slt i32 %iv, 20
|
|
br i1 %cmp, label %for.cond, label %for.end
|
|
|
|
for.end:
|
|
ret i32 0
|
|
}
|