mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
1be380d8da
The description of `isGuaranteedToExecute` does not correspond to its implementation. According to description, it should return `true` if an instruction is executed under the assumption that its loop is *entered*. However there is a sophisticated alrogithm inside that tries to prove that the instruction is executed if the loop is *exited*, which is not the same thing for infinite loops. There is an attempt to protect from dealing with infinite loops by prohibiting loops without exit blocks, however an infinite loop can have exit blocks. As result of that, MustExecute can falsely consider some blocks that are never entered as mustexec, and LICM can hoist dangerous instructions out of them basing on this fact. This may introduce UB to programs which did not contain it initially. This patch removes the problematic algorithm and replaced it with a one which tries to prove what is required in description. Differential Revision: https://reviews.llvm.org/D50558 Reviewed By: reames llvm-svn: 339984
156 lines
4.8 KiB
LLVM
156 lines
4.8 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -disable-output -print-mustexecute %s 2>&1 | FileCheck %s
|
|
|
|
define i1 @header_with_icf(i32* noalias %p, i32 %high) {
|
|
; CHECK-LABEL: @header_with_icf(
|
|
; CHECK-LABEL: loop:
|
|
; CHECK: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] ; (mustexec in: loop)
|
|
; CHECK: %v = load i32, i32* %p ; (mustexec in: loop)
|
|
; CHECK: call void @maythrow_and_use(i32 %v) ; (mustexec in: loop)
|
|
; CHECK-NOT: mustexec
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [0, %entry], [%iv.next, %loop]
|
|
%v = load i32, i32* %p
|
|
call void @maythrow_and_use(i32 %v)
|
|
%iv.next = add nsw nuw i32 %iv, 1
|
|
%exit.test = icmp slt i32 %iv, %high
|
|
br i1 %exit.test, label %exit, label %loop
|
|
|
|
exit:
|
|
ret i1 false
|
|
}
|
|
|
|
define i1 @split_header(i32* noalias %p, i32 %high) {
|
|
; CHECK-LABEL: @split_header(
|
|
; CHECK-LABEL: loop:
|
|
; CHECK: %iv = phi i32 [ 0, %entry ], [ %iv.next, %next ] ; (mustexec in: loop)
|
|
; CHECK: %v = load i32, i32* %p ; (mustexec in: loop)
|
|
; CHECK: br label %next ; (mustexec in: loop)
|
|
; CHECK-NOT: mustexec
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [0, %entry], [%iv.next, %next]
|
|
%v = load i32, i32* %p
|
|
br label %next
|
|
next:
|
|
call void @maythrow_and_use(i32 %v)
|
|
%iv.next = add nsw nuw i32 %iv, 1
|
|
%exit.test = icmp slt i32 %iv, %high
|
|
br i1 %exit.test, label %exit, label %loop
|
|
|
|
exit:
|
|
ret i1 false
|
|
}
|
|
|
|
; FIXME: everything in inner loop header should be must execute
|
|
; for outer as well
|
|
define i1 @nested(i32* noalias %p, i32 %high) {
|
|
; CHECK-LABEL: @nested
|
|
; CHECK-LABEL: loop: ; preds = %next
|
|
; CHECK: %iv = phi i32 [ 0, %entry ], [ %iv.next, %next ] ; (mustexec in: loop)
|
|
; CHECK: br label %inner_loop ; (mustexec in: loop)
|
|
; CHECK-LABEL: inner_loop:
|
|
; CHECK: %v = load i32, i32* %p ; (mustexec in: inner_loop)
|
|
; CHECK: %inner.test = icmp eq i32 %v, 0 ; (mustexec in: inner_loop)
|
|
; CHECK: br i1 %inner.test, label %inner_loop, label %next ; (mustexec in: inner_loop)
|
|
; CHECK-NOT: mustexec
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [0, %entry], [%iv.next, %next]
|
|
br label %inner_loop
|
|
|
|
inner_loop:
|
|
%v = load i32, i32* %p
|
|
%inner.test = icmp eq i32 %v, 0
|
|
br i1 %inner.test, label %inner_loop, label %next
|
|
|
|
next:
|
|
call void @maythrow_and_use(i32 %v)
|
|
%iv.next = add nsw nuw i32 %iv, 1
|
|
%exit.test = icmp slt i32 %iv, %high
|
|
br i1 %exit.test, label %exit, label %loop
|
|
|
|
exit:
|
|
ret i1 false
|
|
}
|
|
|
|
; FIXME: everything in inner loop header should be must execute
|
|
; for outer as well
|
|
define i1 @nested_no_throw(i32* noalias %p, i32 %high) {
|
|
; CHECK-LABEL: @nested_no_throw
|
|
; CHECK-LABEL: loop: ; preds = %next
|
|
; CHECK: %iv = phi i32 [ 0, %entry ], [ %iv.next, %next ] ; (mustexec in: loop)
|
|
; CHECK: br label %inner_loop ; (mustexec in: loop)
|
|
; CHECK-LABEL: inner_loop:
|
|
; CHECK: %v = load i32, i32* %p ; (mustexec in: inner_loop)
|
|
; CHECK: %inner.test = icmp eq i32 %v, 0 ; (mustexec in: inner_loop)
|
|
; CHECK: br i1 %inner.test, label %inner_loop, label %next ; (mustexec in: inner_loop)
|
|
; CHECK-LABEL: next:
|
|
; CHECK: %iv.next = add nuw nsw i32 %iv, 1 ; (mustexec in: loop)
|
|
; CHECK: %exit.test = icmp slt i32 %iv, %high ; (mustexec in: loop)
|
|
; CHECK: br i1 %exit.test, label %exit, label %loop ; (mustexec in: loop)
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [0, %entry], [%iv.next, %next]
|
|
br label %inner_loop
|
|
|
|
inner_loop:
|
|
%v = load i32, i32* %p
|
|
%inner.test = icmp eq i32 %v, 0
|
|
br i1 %inner.test, label %inner_loop, label %next
|
|
|
|
next:
|
|
%iv.next = add nsw nuw i32 %iv, 1
|
|
%exit.test = icmp slt i32 %iv, %high
|
|
br i1 %exit.test, label %exit, label %loop
|
|
|
|
exit:
|
|
ret i1 false
|
|
}
|
|
|
|
; Since all the instructions in the loop dominate the only exit
|
|
; and there's no implicit control flow in the loop, all must execute
|
|
; FIXME: handled by loop safety info, test it
|
|
define i1 @nothrow_loop(i32* noalias %p, i32 %high) {
|
|
; CHECK-LABEL: @nothrow_loop(
|
|
; CHECK-LABEL: loop:
|
|
; CHECK: %iv = phi i32 [ 0, %entry ], [ %iv.next, %next ] ; (mustexec in: loop)
|
|
; CHECK: br label %next ; (mustexec in: loop)
|
|
; CHECK-LABEL: next:
|
|
; CHECK: %v = load i32, i32* %p ; (mustexec in: loop)
|
|
; CHECK: %iv.next = add nuw nsw i32 %iv, 1 ; (mustexec in: loop)
|
|
; CHECK: %exit.test = icmp slt i32 %iv, %high ; (mustexec in: loop)
|
|
; CHECK: br i1 %exit.test, label %exit, label %loop ; (mustexec in: loop)
|
|
; CHECK-NOT: mustexec
|
|
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [0, %entry], [%iv.next, %next]
|
|
br label %next
|
|
next:
|
|
%v = load i32, i32* %p
|
|
%iv.next = add nsw nuw i32 %iv, 1
|
|
%exit.test = icmp slt i32 %iv, %high
|
|
br i1 %exit.test, label %exit, label %loop
|
|
|
|
exit:
|
|
ret i1 false
|
|
}
|
|
|
|
|
|
declare void @maythrow_and_use(i32)
|