mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
23bde48f84
If the only user of `Instr` is in a return or unreachable block, we can sink `Instr` to the`User` safely (unless it reads/writes memory). Return or unreachable blocks are guaranteed to execute zero or one time, and `Instr` always dominates `User`, so they either will be executed together (execution of `User` always implies execution of `Instr`) or not executed at all. Differential Revision: https://reviews.llvm.org/D80120 Reviewed By: asbirlea, jdoerfert
161 lines
4.4 KiB
LLVM
161 lines
4.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -instcombine -S < %s | FileCheck %s
|
|
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
|
|
|
|
declare void @use(i32 %x)
|
|
declare i1 @cond()
|
|
|
|
define void @test_01(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test_01(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[UNREACHED:%.*]]
|
|
; CHECK: unreached:
|
|
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[COMPARATOR:%.*]] = zext i1 [[C1]] to i32
|
|
; CHECK-NEXT: call void @use(i32 [[COMPARATOR]])
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%c1 = icmp eq i32 %x, %y
|
|
%c2 = icmp slt i32 %x, %y
|
|
%signed = select i1 %c2, i32 -1, i32 1
|
|
%comparator = select i1 %c1, i32 0, i32 %signed
|
|
br i1 %c2, label %exit, label %unreached
|
|
|
|
unreached:
|
|
call void @use(i32 %comparator)
|
|
unreachable
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
|
|
define void @test_02(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test_02(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]]
|
|
; CHECK: medium:
|
|
; CHECK-NEXT: [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]]
|
|
; CHECK: unreached:
|
|
; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[SIGNED:%.*]] = select i1 [[C2]], i32 -1, i32 1
|
|
; CHECK-NEXT: [[COMPARATOR:%.*]] = select i1 [[C1]], i32 0, i32 [[SIGNED]]
|
|
; CHECK-NEXT: call void @use(i32 [[COMPARATOR]])
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%c1 = icmp eq i32 %x, %y
|
|
%c2 = icmp slt i32 %x, %y
|
|
%signed = select i1 %c2, i32 -1, i32 1
|
|
%comparator = select i1 %c1, i32 0, i32 %signed
|
|
br i1 %c2, label %exit, label %medium
|
|
|
|
medium:
|
|
%c3 = icmp sgt i32 %x, %y
|
|
br i1 %c3, label %exit, label %unreached
|
|
|
|
unreached:
|
|
call void @use(i32 %comparator)
|
|
unreachable
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define i32 @test_03(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @test_03(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: br i1 [[C2]], label [[EXIT:%.*]], label [[MEDIUM:%.*]]
|
|
; CHECK: medium:
|
|
; CHECK-NEXT: [[C3:%.*]] = icmp sgt i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: br i1 [[C3]], label [[EXIT]], label [[UNREACHED:%.*]]
|
|
; CHECK: unreached:
|
|
; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[X]], [[Y]]
|
|
; CHECK-NEXT: [[SIGNED:%.*]] = select i1 [[C2]], i32 -1, i32 1
|
|
; CHECK-NEXT: [[COMPARATOR:%.*]] = select i1 [[C1]], i32 0, i32 [[SIGNED]]
|
|
; CHECK-NEXT: ret i32 [[COMPARATOR]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
entry:
|
|
%c1 = icmp eq i32 %x, %y
|
|
%c2 = icmp slt i32 %x, %y
|
|
%signed = select i1 %c2, i32 -1, i32 1
|
|
%comparator = select i1 %c1, i32 0, i32 %signed
|
|
br i1 %c2, label %exit, label %medium
|
|
|
|
medium:
|
|
%c3 = icmp sgt i32 %x, %y
|
|
br i1 %c3, label %exit, label %unreached
|
|
|
|
unreached:
|
|
ret i32 %comparator
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_04(i32 %x, i1 %c) {
|
|
; CHECK-LABEL: @test_04(
|
|
; CHECK-NEXT: bb0:
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
|
|
; CHECK: bb1:
|
|
; CHECK-NEXT: br label [[BB3:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br label [[BB3]]
|
|
; CHECK: bb3:
|
|
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ 1, [[BB2]] ]
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[R:%.*]] = add i32 [[P]], [[A]]
|
|
; CHECK-NEXT: ret i32 [[R]]
|
|
;
|
|
bb0:
|
|
%a = add i32 %x, 1
|
|
br i1 %c, label %bb1, label %bb2
|
|
bb1:
|
|
br label %bb3
|
|
bb2:
|
|
br label %bb3
|
|
bb3:
|
|
%p = phi i32 [0, %bb1], [1, %bb2]
|
|
%r = add i32 %p, %a
|
|
ret i32 %r
|
|
}
|
|
|
|
; Do not sink into a potentially hotter block.
|
|
define i32 @test_05_neg(i32 %x, i1 %cond) {
|
|
; CHECK-LABEL: @test_05_neg(
|
|
; CHECK-NEXT: bb0:
|
|
; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
|
|
; CHECK: bb1:
|
|
; CHECK-NEXT: br label [[BB3:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[CALL]], label [[BB2]], label [[BB3]]
|
|
; CHECK: bb3:
|
|
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[BB1]] ], [ [[A]], [[BB2]] ]
|
|
; CHECK-NEXT: ret i32 [[P]]
|
|
;
|
|
bb0:
|
|
%a = add i32 %x, 1
|
|
br i1 %cond, label %bb1, label %bb2
|
|
bb1:
|
|
br label %bb3
|
|
bb2:
|
|
%call = call i1 @cond()
|
|
br i1 %call, label %bb2, label %bb3
|
|
bb3:
|
|
%p = phi i32 [0, %bb1], [%a, %bb2]
|
|
ret i32 %p
|
|
}
|