mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
a4f9bca98e
Turns out simplifyLoopIVs sometimes returns a non-dead instruction in it's DeadInsts out param. I had done a bit of NFC cleanup which was only NFC if simplifyLoopIVs obeyed it's documentation. I'm simplfy dropping that part of the change. Commit message from try 3: Recommitting after fixing a bug found post commit. Amusingly, try 1 had been correct, and by reverting to incorporate last minute review feedback, I introduce the bug. Oops. :) Original commit message: The problem was that recursively deleting an instruction can delete instructions beyond the current iterator (via a dead phi), thus invalidating iteration. Test case added in LoopUnroll/dce.ll to cover this case. LoopUnroll does a limited DCE pass after unrolling, but if you have a chain of dead instructions, it only deletes the last one. Improve the code to recursively delete all trivially dead instructions. Differential Revision: https://reviews.llvm.org/D102511
280 lines
9.9 KiB
LLVM
280 lines
9.9 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -loop-unroll -S %s -verify-loop-info -verify-dom-info -verify-loop-lcssa | FileCheck %s
|
|
|
|
%struct.spam = type { double, double, double, double, double, double, double }
|
|
|
|
define void @test2(i32* %arg) {
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[FOR_HEADER:%.*]]
|
|
; CHECK: for.header:
|
|
; CHECK-NEXT: store i32 0, i32* [[ARG:%.*]], align 4
|
|
; CHECK-NEXT: br label [[FOR_LATCH:%.*]]
|
|
; CHECK: for.latch:
|
|
; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 1
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR_1]], align 4
|
|
; CHECK-NEXT: br label [[FOR_LATCH_1:%.*]]
|
|
; CHECK: if.end.loopexit:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: for.latch.1:
|
|
; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 2
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR_2]], align 4
|
|
; CHECK-NEXT: br label [[FOR_LATCH_2:%.*]]
|
|
; CHECK: for.latch.2:
|
|
; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 3
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR_3]], align 4
|
|
; CHECK-NEXT: br i1 true, label [[IF_END_LOOPEXIT:%.*]], label [[FOR_LATCH_3:%.*]]
|
|
; CHECK: for.latch.3:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
entry:
|
|
br label %for.header
|
|
|
|
for.header: ; preds = %for.latch, %entry
|
|
%indvars.iv800 = phi i64 [ 0, %entry ], [ %indvars.iv.next801, %for.latch ]
|
|
%ptr = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv800
|
|
store i32 0, i32* %ptr, align 4
|
|
%indvars.iv.next801 = add nuw nsw i64 %indvars.iv800, 1
|
|
%exitcond802 = icmp eq i64 %indvars.iv.next801, 4
|
|
br i1 %exitcond802, label %if.end.loopexit, label %for.latch
|
|
|
|
for.latch: ; preds = %for.header
|
|
br label %for.header
|
|
|
|
if.end.loopexit: ; preds = %for.header
|
|
ret void
|
|
}
|
|
|
|
define double @test_with_lcssa(double %arg1, double* %arg2) {
|
|
; CHECK-LABEL: @test_with_lcssa(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
|
|
; CHECK: loop.header:
|
|
; CHECK-NEXT: [[RES:%.*]] = fsub double [[ARG1:%.*]], 3.000000e+00
|
|
; CHECK-NEXT: br label [[LOOP_LATCH:%.*]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds double, double* [[ARG2:%.*]], i64 1
|
|
; CHECK-NEXT: [[LV:%.*]] = load double, double* [[PTR]], align 8
|
|
; CHECK-NEXT: [[RES_1:%.*]] = fsub double [[LV]], [[RES]]
|
|
; CHECK-NEXT: br i1 true, label [[LOOP_EXIT:%.*]], label [[LOOP_LATCH_1:%.*]]
|
|
; CHECK: loop.exit:
|
|
; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi double [ [[RES_1]], [[LOOP_LATCH]] ]
|
|
; CHECK-NEXT: ret double [[RES_LCSSA]]
|
|
; CHECK: loop.latch.1:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header: ; preds = %entry, %loop.latch
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%d1 = phi double [ %arg1, %entry ], [ %lv, %loop.latch ]
|
|
%d2 = phi double [ 3.0, %entry ], [ %res, %loop.latch ]
|
|
%res = fsub double %d1, %d2
|
|
%iv.next = add nuw nsw i64 %iv, 1
|
|
%cond = icmp eq i64 %iv.next, 2
|
|
br i1 %cond, label %loop.exit, label %loop.latch
|
|
|
|
loop.latch: ; preds = %bb366
|
|
%ptr = getelementptr inbounds double, double* %arg2, i64 %iv.next
|
|
%lv = load double, double* %ptr, align 8
|
|
br label %loop.header
|
|
|
|
loop.exit: ; preds = %bb366
|
|
%res.lcssa = phi double [ %res, %loop.header ]
|
|
ret double %res.lcssa
|
|
}
|
|
|
|
; We unroll the outer loop and need to preserve LI for the inner loop.
|
|
define void @test_with_nested_loop(i32* %arg) {
|
|
; CHECK-LABEL: @test_with_nested_loop(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
|
|
; CHECK: outer.header:
|
|
; CHECK-NEXT: br label [[INNER_BODY_PREHEADER:%.*]]
|
|
; CHECK: inner.body.preheader:
|
|
; CHECK-NEXT: br label [[INNER_BODY:%.*]]
|
|
; CHECK: inner.body:
|
|
; CHECK-NEXT: [[J_IV:%.*]] = phi i64 [ [[J_IV_NEXT:%.*]], [[INNER_BODY]] ], [ 0, [[INNER_BODY_PREHEADER]] ]
|
|
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, i32* [[ARG:%.*]], i64 [[J_IV]]
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR]], align 4
|
|
; CHECK-NEXT: [[J_IV_NEXT]] = add nuw nsw i64 [[J_IV]], 1
|
|
; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i64 [[J_IV_NEXT]], 40000
|
|
; CHECK-NEXT: br i1 [[INNER_COND]], label [[OUTER_LATCH:%.*]], label [[INNER_BODY]]
|
|
; CHECK: outer.latch:
|
|
; CHECK-NEXT: br label [[INNER_BODY_PREHEADER_1:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
; CHECK: inner.body.preheader.1:
|
|
; CHECK-NEXT: br label [[INNER_BODY_1:%.*]]
|
|
; CHECK: inner.body.1:
|
|
; CHECK-NEXT: [[J_IV_1:%.*]] = phi i64 [ [[J_IV_NEXT_1:%.*]], [[INNER_BODY_1]] ], [ 0, [[INNER_BODY_PREHEADER_1]] ]
|
|
; CHECK-NEXT: [[IDX_1:%.*]] = add i64 1, [[J_IV_1]]
|
|
; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 [[IDX_1]]
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR_1]], align 4
|
|
; CHECK-NEXT: [[J_IV_NEXT_1]] = add nuw nsw i64 [[J_IV_1]], 1
|
|
; CHECK-NEXT: [[INNER_COND_1:%.*]] = icmp eq i64 [[J_IV_NEXT_1]], 40000
|
|
; CHECK-NEXT: br i1 [[INNER_COND_1]], label [[OUTER_LATCH_1:%.*]], label [[INNER_BODY_1]]
|
|
; CHECK: outer.latch.1:
|
|
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER_2:%.*]]
|
|
; CHECK: inner.body.preheader.2:
|
|
; CHECK-NEXT: br label [[INNER_BODY_2:%.*]]
|
|
; CHECK: inner.body.2:
|
|
; CHECK-NEXT: [[J_IV_2:%.*]] = phi i64 [ [[J_IV_NEXT_2:%.*]], [[INNER_BODY_2]] ], [ 0, [[INNER_BODY_PREHEADER_2]] ]
|
|
; CHECK-NEXT: [[IDX_2:%.*]] = add i64 2, [[J_IV_2]]
|
|
; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 [[IDX_2]]
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR_2]], align 4
|
|
; CHECK-NEXT: [[J_IV_NEXT_2]] = add nuw nsw i64 [[J_IV_2]], 1
|
|
; CHECK-NEXT: [[INNER_COND_2:%.*]] = icmp eq i64 [[J_IV_NEXT_2]], 40000
|
|
; CHECK-NEXT: br i1 [[INNER_COND_2]], label [[OUTER_LATCH_2:%.*]], label [[INNER_BODY_2]]
|
|
; CHECK: outer.latch.2:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
entry:
|
|
br label %outer.header
|
|
|
|
outer.header: ; preds = %outer.latch, %entry
|
|
%outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
|
|
%outer.iv.next = add nuw nsw i64 %outer.iv, 1
|
|
%outer.cond = icmp eq i64 %outer.iv, 2
|
|
br i1 %outer.cond, label %exit, label %inner.body
|
|
|
|
inner.body:
|
|
%j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ]
|
|
%idx = add i64 %outer.iv, %j.iv
|
|
%ptr = getelementptr inbounds i32, i32* %arg, i64 %idx
|
|
store i32 0, i32* %ptr, align 4
|
|
%j.iv.next = add nuw nsw i64 %j.iv, 1
|
|
%inner.cond = icmp eq i64 %j.iv.next, 40000
|
|
br i1 %inner.cond, label %outer.latch, label %inner.body
|
|
|
|
outer.latch: ; preds = %inner.body
|
|
br label %outer.header
|
|
|
|
exit: ; preds = %outer.header
|
|
ret void
|
|
}
|
|
|
|
; We unroll the inner loop and need to preserve LI for the outer loop.
|
|
define void @test_with_nested_loop_unroll_inner(i32* %arg) {
|
|
; CHECK-LABEL: @test_with_nested_loop_unroll_inner(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
|
|
; CHECK: outer.header:
|
|
; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[INNER_BODY:%.*]] ]
|
|
; CHECK-NEXT: [[OUTER_IV_NEXT]] = add nuw nsw i64 [[OUTER_IV]], 1
|
|
; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i64 [[OUTER_IV]], 40000
|
|
; CHECK-NEXT: br i1 [[OUTER_COND]], label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER:%.*]]
|
|
; CHECK: inner.body.preheader:
|
|
; CHECK-NEXT: br label [[INNER_BODY]]
|
|
; CHECK: inner.body:
|
|
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, i32* [[ARG:%.*]], i64 [[OUTER_IV]]
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR]], align 4
|
|
; CHECK-NEXT: [[IDX_1:%.*]] = add i64 [[OUTER_IV]], 1
|
|
; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 [[IDX_1]]
|
|
; CHECK-NEXT: store i32 0, i32* [[PTR_1]], align 4
|
|
; CHECK-NEXT: br label [[OUTER_HEADER]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
|
|
|
|
|
|
entry:
|
|
br label %outer.header
|
|
|
|
outer.header: ; preds = %outer.latch, %entry
|
|
%outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
|
|
%outer.iv.next = add nuw nsw i64 %outer.iv, 1
|
|
%outer.cond = icmp eq i64 %outer.iv, 40000
|
|
br i1 %outer.cond, label %exit, label %inner.body
|
|
|
|
inner.body:
|
|
%j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ]
|
|
%idx = add i64 %outer.iv, %j.iv
|
|
%ptr = getelementptr inbounds i32, i32* %arg, i64 %idx
|
|
store i32 0, i32* %ptr, align 4
|
|
%j.iv.next = add nuw nsw i64 %j.iv, 1
|
|
%inner.cond = icmp eq i64 %j.iv.next, 2
|
|
br i1 %inner.cond, label %outer.latch, label %inner.body
|
|
|
|
outer.latch: ; preds = %inner.body
|
|
br label %outer.header
|
|
|
|
exit: ; preds = %outer.header
|
|
ret void
|
|
}
|
|
|
|
|
|
|
|
; Check that we do not crash for headers with non-branch instructions, e.g.
|
|
; switch. We do not unroll in those cases.
|
|
define void @test_switchinst_in_header() {
|
|
; CHECK-LABEL: @test_switchinst_in_header(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[WHILE_HEADER:%.*]]
|
|
; CHECK: while.header:
|
|
; CHECK-NEXT: switch i32 undef, label [[EXIT:%.*]] [
|
|
; CHECK-NEXT: i32 11, label [[WHILE_BODY1:%.*]]
|
|
; CHECK-NEXT: i32 5, label [[WHILE_BODY2:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: while.body1:
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: while.body2:
|
|
; CHECK-NEXT: br label [[WHILE_LATCH:%.*]]
|
|
; CHECK: while.latch:
|
|
; CHECK-NEXT: br label [[WHILE_HEADER]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
entry:
|
|
br label %while.header
|
|
|
|
while.header: ; preds = %while.latch, %entry
|
|
switch i32 undef, label %exit [
|
|
i32 11, label %while.body1
|
|
i32 5, label %while.body2
|
|
]
|
|
|
|
while.body1: ; preds = %while.header
|
|
unreachable
|
|
|
|
while.body2: ; preds = %while.header
|
|
br label %while.latch
|
|
|
|
while.latch: ; preds = %while.body2
|
|
br label %while.header
|
|
|
|
exit: ; preds = %while.header
|
|
ret void
|
|
}
|