aboutsummaryrefslogtreecommitdiff
path: root/llvm/test/Transforms/InstCombine
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/InstCombine')
-rw-r--r--llvm/test/Transforms/InstCombine/fcmp.ll40
-rw-r--r--llvm/test/Transforms/InstCombine/freeze-phi.ll28
-rw-r--r--llvm/test/Transforms/InstCombine/freeze.ll21
-rw-r--r--llvm/test/Transforms/InstCombine/funnel.ll26
-rw-r--r--llvm/test/Transforms/InstCombine/icmp-clamp.ll295
-rw-r--r--llvm/test/Transforms/InstCombine/in-freeze-phi.ll274
6 files changed, 684 insertions, 0 deletions
diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll
index 119cffd..d94e78c 100644
--- a/llvm/test/Transforms/InstCombine/fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp.ll
@@ -1812,6 +1812,46 @@ define i1 @fcmp_ule_fsub_const(float %x, float %y) {
ret i1 %cmp
}
+define i1 @fcmp_ninf_ule_fsub_const(float %x, float %y) {
+; CHECK-LABEL: @fcmp_ninf_ule_fsub_const(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ule float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %fs = fsub float %x, %y
+ %cmp = fcmp ninf ule float %fs, 0.000000e+00
+ ret i1 %cmp
+}
+
+define i1 @fcmp_nnan_ule_fsub_const(float %x, float %y) {
+; CHECK-LABEL: @fcmp_nnan_ule_fsub_const(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan ule float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %fs = fsub float %x, %y
+ %cmp = fcmp nnan ule float %fs, 0.000000e+00
+ ret i1 %cmp
+}
+
+define i1 @fcmp_ule_fsub_ninf_const(float %x, float %y) {
+; CHECK-LABEL: @fcmp_ule_fsub_ninf_const(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ule float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %fs = fsub ninf float %x, %y
+ %cmp = fcmp ule float %fs, 0.000000e+00
+ ret i1 %cmp
+}
+
+define i1 @fcmp_ule_fsub_nnan_const(float %x, float %y) {
+; CHECK-LABEL: @fcmp_ule_fsub_nnan_const(
+; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan ule float [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %fs = fsub nnan float %x, %y
+ %cmp = fcmp ule float %fs, 0.000000e+00
+ ret i1 %cmp
+}
+
define i1 @fcmp_ugt_fsub_const(float %x, float %y) {
; CHECK-LABEL: @fcmp_ugt_fsub_const(
; CHECK-NEXT: [[FS:%.*]] = fsub float [[X:%.*]], [[Y:%.*]]
diff --git a/llvm/test/Transforms/InstCombine/freeze-phi.ll b/llvm/test/Transforms/InstCombine/freeze-phi.ll
index cdc9a5e..62bb9dc3 100644
--- a/llvm/test/Transforms/InstCombine/freeze-phi.ll
+++ b/llvm/test/Transforms/InstCombine/freeze-phi.ll
@@ -212,3 +212,31 @@ D:
%y.fr = freeze i32 %y
ret i32 %y.fr
}
+
+; Make sure that fmf in phi node is dropped when freeze get folded.
+
+define float @pr161524(float noundef %arg) {
+; CHECK-LABEL: @pr161524(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND:%.*]] = tail call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 144)
+; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_EXIT:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[FADD:%.*]] = fadd float [[ARG]], 1.000000e+00
+; CHECK-NEXT: br label [[IF_EXIT]]
+; CHECK: if.exit:
+; CHECK-NEXT: [[RET:%.*]] = phi float [ [[FADD]], [[IF_THEN]] ], [ [[ARG]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret float [[RET]]
+;
+entry:
+ %cond = tail call i1 @llvm.is.fpclass.f32(float %arg, i32 144)
+ br i1 %cond, label %if.then, label %if.exit
+
+if.then:
+ %fadd = fadd float %arg, 1.0
+ br label %if.exit
+
+if.exit:
+ %ret = phi ninf float [ %fadd, %if.then ], [ %arg, %entry ]
+ %ret.fr = freeze float %ret
+ ret float %ret.fr
+}
diff --git a/llvm/test/Transforms/InstCombine/freeze.ll b/llvm/test/Transforms/InstCombine/freeze.ll
index af5cb0c..ac7d65c 100644
--- a/llvm/test/Transforms/InstCombine/freeze.ll
+++ b/llvm/test/Transforms/InstCombine/freeze.ll
@@ -1464,6 +1464,27 @@ define ptr @freeze_ptrmask_nonnull(ptr %p, i64 noundef %m) {
ret ptr %fr
}
+define i64 @pr161492_1(i1 %cond) {
+; CHECK-LABEL: define i64 @pr161492_1(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: ret i64 0
+;
+ %fr1 = freeze i64 poison
+ %fr2 = freeze i64 poison
+ %ret = select i1 %cond, i64 %fr1, i64 %fr2
+ ret i64 %ret
+}
+
+define i64 @pr161492_2(i1 %cond) {
+; CHECK-LABEL: define i64 @pr161492_2(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: ret i64 0
+;
+ %fr = freeze i64 poison
+ %ret = select i1 %cond, i64 %fr, i64 %fr
+ ret i64 %ret
+}
+
!0 = !{}
!1 = !{i64 4}
!2 = !{i32 0, i32 100}
diff --git a/llvm/test/Transforms/InstCombine/funnel.ll b/llvm/test/Transforms/InstCombine/funnel.ll
index 0e5f046..e573108 100644
--- a/llvm/test/Transforms/InstCombine/funnel.ll
+++ b/llvm/test/Transforms/InstCombine/funnel.ll
@@ -635,3 +635,29 @@ define i32 @test_rotl_and_neg_wrong_mask(i32 %x, i32 %shamt) {
%or = or i32 %shl, %shr
ret i32 %or
}
+
+declare void @use(i16)
+
+; Make sure the reused result does not produce poison.
+
+define i16 @fshl_concat_vector_may_produce_poison(i4 %x, i12 %y) {
+; CHECK-LABEL: @fshl_concat_vector_may_produce_poison(
+; CHECK-NEXT: [[X_FR:%.*]] = freeze i4 [[X:%.*]]
+; CHECK-NEXT: [[ZEXT_X:%.*]] = zext i4 [[X_FR]] to i16
+; CHECK-NEXT: [[SLX:%.*]] = shl nuw i16 [[ZEXT_X]], 12
+; CHECK-NEXT: [[ZEXT_Y:%.*]] = zext i12 [[Y:%.*]] to i16
+; CHECK-NEXT: [[XY:%.*]] = or disjoint i16 [[SLX]], [[ZEXT_Y]]
+; CHECK-NEXT: call void @use(i16 [[XY]])
+; CHECK-NEXT: [[YX:%.*]] = call i16 @llvm.fshl.i16(i16 [[XY]], i16 [[XY]], i16 4)
+; CHECK-NEXT: ret i16 [[YX]]
+;
+ %x.fr = freeze i4 %x
+ %zext.x = zext i4 %x.fr to i16
+ %slx = shl nuw nsw i16 %zext.x, 12
+ %zext.y = zext i12 %y to i16
+ %xy = or disjoint i16 %slx, %zext.y
+ call void @use(i16 %xy)
+ %sly = shl nuw i16 %zext.y, 4
+ %yx = or disjoint i16 %sly, %zext.x
+ ret i16 %yx
+}
diff --git a/llvm/test/Transforms/InstCombine/icmp-clamp.ll b/llvm/test/Transforms/InstCombine/icmp-clamp.ll
new file mode 100644
index 0000000..4866dbf
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-clamp.ll
@@ -0,0 +1,295 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @use(i32)
+
+define i1 @test_i32_eq(i32 %x) {
+; CHECK-LABEL: define i1 @test_i32_eq(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 95
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 256
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_i32_ne(i32 %x) {
+; CHECK-LABEL: define i1 @test_i32_ne(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -161
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -256
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp ne i32 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_i32_eq_no_add(i32 %x) {
+; CHECK-LABEL: define i1 @test_i32_eq_no_add(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X]], 161
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 0)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_i32_ne_no_add(i32 %x) {
+; CHECK-LABEL: define i1 @test_i32_ne_no_add(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 160
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 0)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp ne i32 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_unsigned_eq(i32 %x) {
+; CHECK-LABEL: define i1 @test_unsigned_eq(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -10
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 91
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
+ %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 100)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_unsigned_ne(i32 %x) {
+; CHECK-LABEL: define i1 @test_unsigned_ne(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -101
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], -91
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
+ %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 100)
+ %cmp = icmp ne i32 %v2, %x
+ ret i1 %cmp
+}
+
+
+; Different bit widths
+define i1 @test_i8_eq(i8 %x) {
+; CHECK-LABEL: define i1 @test_i8_eq(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X]], 50
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP1]], 101
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i8 @llvm.smax.i8(i8 %x, i8 -50)
+ %v2 = tail call i8 @llvm.smin.i8(i8 %v1, i8 50)
+ %cmp = icmp eq i8 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_i16_eq(i16 %x) {
+; CHECK-LABEL: define i1 @test_i16_eq(
+; CHECK-SAME: i16 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[X]], 1000
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[TMP1]], 2001
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i16 @llvm.smax.i16(i16 %x, i16 -1000)
+ %v2 = tail call i16 @llvm.smin.i16(i16 %v1, i16 1000)
+ %cmp = icmp eq i16 %v2, %x
+ ret i1 %cmp
+}
+
+define i1 @test_i64_eq(i64 %x) {
+; CHECK-LABEL: define i1 @test_i64_eq(
+; CHECK-SAME: i64 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[TMP1]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i64 @llvm.smax.i64(i64 %x, i64 -1)
+ %v2 = tail call i64 @llvm.smin.i64(i64 %v1, i64 9223372036854775806)
+ %cmp = icmp eq i64 %v2, %x
+ ret i1 %cmp
+}
+
+; Negative tests - wrong predicate
+define i1 @test_wrong_pred_slt(i32 %x) {
+; CHECK-LABEL: define i1 @test_wrong_pred_slt(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], 160
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp slt i32 %v2, %x
+ ret i1 %cmp
+}
+
+
+; Negative tests - not a clamp pattern
+define i1 @test_not_clamp_pattern(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @test_not_clamp_pattern(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[Y]], i32 -95)
+; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %y, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Negative tests - Lo >= Hi
+define i1 @test_invalid_range(i32 %x) {
+; CHECK-LABEL: define i1 @test_invalid_range(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 50
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 100)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 50)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Negative tests - Lo is minimum signed value
+define i1 @test_lo_min_signed(i32 %x) {
+; CHECK-LABEL: define i1 @test_lo_min_signed(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], 161
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -2147483648)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Negative tests - Hi is maximum signed value
+define i1 @test_hi_max_signed(i32 %x) {
+; CHECK-LABEL: define i1 @test_hi_max_signed(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], -96
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 2147483647)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Negative tests - Hi is maximum unsigned value
+define i1 @test_hi_max_unsigned(i32 %x) {
+; CHECK-LABEL: define i1 @test_hi_max_unsigned(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 9
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.umax.i32(i32 %x, i32 10)
+ %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 4294967295)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Multi-use tests - multiple uses of max
+define i1 @test_multi_use_max(i32 %x) {
+; CHECK-LABEL: define i1 @test_multi_use_max(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
+; CHECK-NEXT: call void @use(i32 [[V1]])
+; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ call void @use(i32 %v1)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Multi-use tests - multiple uses of min
+define i1 @test_multi_use_min(i32 %x) {
+; CHECK-LABEL: define i1 @test_multi_use_min(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[V1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[X]], i32 -95)
+; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 160)
+; CHECK-NEXT: call void @use(i32 [[V2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V2]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ call void @use(i32 %v2)
+ %cmp = icmp eq i32 %v2, %x
+ ret i1 %cmp
+}
+
+; Commuted tests
+define i1 @test_commuted_eq(i32 %x) {
+; CHECK-LABEL: define i1 @test_commuted_eq(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 95
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], 256
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %v1 = tail call i32 @llvm.smax.i32(i32 %x, i32 -95)
+ %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 160)
+ %cmp = icmp eq i32 %x, %v2
+ ret i1 %cmp
+}
+
+
+; Vector tests - splat constants
+define <2 x i1> @test_vec_splat_eq(<2 x i32> %x) {
+; CHECK-LABEL: define <2 x i1> @test_vec_splat_eq(
+; CHECK-SAME: <2 x i32> [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X]], splat (i32 50)
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i32> [[TMP1]], splat (i32 101)
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 -50>)
+ %v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 50>)
+ %cmp = icmp eq <2 x i32> %v2, %x
+ ret <2 x i1> %cmp
+}
+
+; Vector tests - poison elements
+define <2 x i1> @test_vec_poison_eq(<2 x i32> %x) {
+; CHECK-LABEL: define <2 x i1> @test_vec_poison_eq(
+; CHECK-SAME: <2 x i32> [[X:%.*]]) {
+; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> <i32 -50, i32 poison>)
+; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> <i32 50, i32 poison>)
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 poison>)
+ %v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 poison>)
+ %cmp = icmp eq <2 x i32> %v2, %x
+ ret <2 x i1> %cmp
+}
+
+; Vector tests - non-splat
+define <2 x i1> @test_vec_non_splat_eq(<2 x i32> %x) {
+; CHECK-LABEL: define <2 x i1> @test_vec_non_splat_eq(
+; CHECK-SAME: <2 x i32> [[X:%.*]]) {
+; CHECK-NEXT: [[V1:%.*]] = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[X]], <2 x i32> <i32 -50, i32 -30>)
+; CHECK-NEXT: [[V2:%.*]] = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[V1]], <2 x i32> <i32 50, i32 70>)
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[V2]], [[X]]
+; CHECK-NEXT: ret <2 x i1> [[CMP]]
+;
+ %v1 = tail call <2 x i32> @llvm.smax.v2i32(<2 x i32> %x, <2 x i32> <i32 -50, i32 -30>)
+ %v2 = tail call <2 x i32> @llvm.smin.v2i32(<2 x i32> %v1, <2 x i32> <i32 50, i32 70>)
+ %cmp = icmp eq <2 x i32> %v2, %x
+ ret <2 x i1> %cmp
+}
diff --git a/llvm/test/Transforms/InstCombine/in-freeze-phi.ll b/llvm/test/Transforms/InstCombine/in-freeze-phi.ll
new file mode 100644
index 0000000..917d81b
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/in-freeze-phi.ll
@@ -0,0 +1,274 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+define i32 @phi_freeze_same_consts(i1 %c0, i1 %c1) {
+; CHECK-LABEL: define i32 @phi_freeze_same_consts(
+; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
+; CHECK: [[BB_FREEZE]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: ret i32 42
+;
+entry:
+ br i1 %c0, label %bb_freeze, label %bb_other
+
+bb_freeze:
+ %f = freeze i32 undef
+ br label %final
+
+bb_other:
+ br i1 %c1, label %cA, label %cB
+cA:
+ br label %final
+cB:
+ br label %final
+
+final:
+ %phi = phi i32 [ %f, %bb_freeze ], [ 42, %cA ], [ 42, %cB ]
+ ret i32 %phi
+}
+
+define i32 @phi_freeze_mixed_consts(i1 %c0, i1 %c1) {
+; CHECK-LABEL: define i32 @phi_freeze_mixed_consts(
+; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
+; CHECK: [[BB_FREEZE]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, %[[BB_FREEZE]] ], [ 42, %[[CA]] ], [ 7, %[[CB]] ]
+; CHECK-NEXT: ret i32 [[PHI]]
+;
+entry:
+ br i1 %c0, label %bb_freeze, label %bb_other
+
+bb_freeze:
+ %f = freeze i32 undef
+ br label %final
+
+bb_other:
+ br i1 %c1, label %cA, label %cB
+cA:
+ br label %final
+cB:
+ br label %final
+
+final:
+ %phi = phi i32 [ %f, %bb_freeze ], [ 42, %cA ], [ 7, %cB ]
+ ret i32 %phi
+}
+
+define i32 @phi_freeze_with_nonconst_incoming(i32 %x, i1 %c0, i1 %c1) {
+; CHECK-LABEL: define i32 @phi_freeze_with_nonconst_incoming(
+; CHECK-SAME: i32 [[X:%.*]], i1 [[C0:%.*]], i1 [[C1:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
+; CHECK: [[BB_FREEZE]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, %[[BB_FREEZE]] ], [ [[X]], %[[CA]] ], [ 13, %[[CB]] ]
+; CHECK-NEXT: ret i32 [[PHI]]
+;
+entry:
+ br i1 %c0, label %bb_freeze, label %bb_other
+
+bb_freeze:
+ %f = freeze i32 undef
+ br label %final
+
+bb_other:
+ br i1 %c1, label %cA, label %cB
+cA:
+ br label %final
+cB:
+ br label %final
+
+final:
+ %phi = phi i32 [ %f, %bb_freeze ], [ %x, %cA ], [ 13, %cB ]
+ ret i32 %phi
+}
+
+define <4 x i8> @phi_freeze_vector(i1 %c0, i1 %c1) {
+; CHECK-LABEL: define <4 x i8> @phi_freeze_vector(
+; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
+; CHECK: [[BB_FREEZE]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: ret <4 x i8> splat (i8 9)
+;
+entry:
+ br i1 %c0, label %bb_freeze, label %bb_other
+
+bb_freeze:
+ %f = freeze <4 x i8> undef
+ br label %final
+
+bb_other:
+ br i1 %c1, label %cA, label %cB
+
+cA:
+ br label %final
+
+cB:
+ br label %final
+
+final:
+ %phi = phi <4 x i8> [ %f, %bb_freeze ],
+ [<i8 9, i8 9, i8 9, i8 9>, %cA ],
+ [<i8 9, i8 9, i8 9, i8 9>, %cB ]
+ ret <4 x i8> %phi
+}
+
+define i32 @multi_use_one_folds_one_not_zero(i1 %c0, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i32 @multi_use_one_folds_one_not_zero(
+; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_OTHER3:.*]], label %[[CC1:.*]]
+; CHECK: [[BB_OTHER3]]:
+; CHECK-NEXT: br label %[[MID:.*]]
+; CHECK: [[CC1]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[MID]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[MID]]
+; CHECK: [[MID]]:
+; CHECK-NEXT: [[PHI_FOLD:%.*]] = phi i32 [ 0, %[[BB_OTHER3]] ], [ 1, %[[CA]] ], [ 1, %[[CB]] ]
+; CHECK-NEXT: br i1 [[C2]], label %[[BB_FREEZE2:.*]], label %[[CD:.*]]
+; CHECK: [[BB_FREEZE2]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER2:.*:]]
+; CHECK-NEXT: br i1 true, label %[[CA]], label %[[CB]]
+; CHECK: [[CC:.*:]]
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CD]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: ret i32 [[PHI_FOLD]]
+;
+entry:
+ %f = freeze i32 undef
+ br i1 %c0, label %bb_freeze, label %bb_other
+bb_freeze:
+ br label %mid
+bb_other:
+ br i1 %c1, label %cA, label %cB
+cA:
+ br label %mid
+cB:
+ br label %mid
+mid:
+ %phi_no_fold = phi i32 [ %f, %bb_freeze ], [ 1, %cA ], [ 1, %cB ]
+ br i1 %c2, label %bb_freeze2, label %cD
+bb_freeze2:
+ br label %final
+bb_other2:
+ br i1 %c1, label %cA, label %cB
+cC:
+ br label %final
+cD:
+ br label %final
+final:
+ %phi_fold = phi i32 [ %f, %bb_freeze2 ], [ 0, %cC ], [ 0, %cD ]
+ %a = add i32 %phi_fold, %phi_no_fold
+ ret i32 %a
+}
+
+define i32 @phi_freeze_poison(i1 %c0, i1 %c1) {
+; CHECK-LABEL: define i32 @phi_freeze_poison(
+; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
+; CHECK: [[BB_FREEZE]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ br i1 %c0, label %bb_freeze, label %bb_other
+
+bb_freeze:
+ %f = freeze i32 undef
+ br label %final
+
+bb_other:
+ br i1 %c1, label %cA, label %cB
+cA:
+ br label %final
+cB:
+ br label %final
+
+final:
+ %phi = phi i32 [ %f, %bb_freeze ], [ poison, %cA ], [ poison, %cB ]
+ ret i32 %phi
+}
+
+define <2 x i32> @phi_freeze_poison_vec(i1 %c0, i1 %c1) {
+; CHECK-LABEL: define <2 x i32> @phi_freeze_poison_vec(
+; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br i1 [[C0]], label %[[BB_FREEZE:.*]], label %[[BB_OTHER:.*]]
+; CHECK: [[BB_FREEZE]]:
+; CHECK-NEXT: br label %[[FINAL:.*]]
+; CHECK: [[BB_OTHER]]:
+; CHECK-NEXT: br i1 [[C1]], label %[[CA:.*]], label %[[CB:.*]]
+; CHECK: [[CA]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[CB]]:
+; CHECK-NEXT: br label %[[FINAL]]
+; CHECK: [[FINAL]]:
+; CHECK-NEXT: [[PHI:%.*]] = phi <2 x i32> [ zeroinitializer, %[[BB_FREEZE]] ], [ <i32 poison, i32 1>, %[[CA]] ], [ <i32 poison, i32 1>, %[[CB]] ]
+; CHECK-NEXT: ret <2 x i32> [[PHI]]
+;
+entry:
+ br i1 %c0, label %bb_freeze, label %bb_other
+
+bb_freeze:
+ %f = freeze <2 x i32> undef
+ br label %final
+
+bb_other:
+ br i1 %c1, label %cA, label %cB
+cA:
+ br label %final
+cB:
+ br label %final
+
+final:
+ %phi = phi <2 x i32> [ %f, %bb_freeze ], [ <i32 poison, i32 1>, %cA ], [ <i32 poison, i32 1>, %cB ]
+ ret <2 x i32> %phi
+}