blob: ac286040aafa71b67d65b8d4b095828a258d7938 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare void @use_double(double)
;; ============================================================
;; Core pattern: fcmp une (select C1, K, K'), (select C2, K, K') → xor
;; Truth table: {(0,0):false, (0,1):true, (1,0):true, (1,1):false} = 0b0110
;; ============================================================
define i1 @fcmp_une_select_same_consts(double %a, double %b) {
; CHECK-LABEL: @fcmp_une_select_same_consts(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp ult double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[V2]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
%v4 = fcmp une double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; fcmp oeq → xnor
;; Truth table: 0b1001
;; ============================================================
define i1 @fcmp_oeq_select_same_consts(double %a, double %b) {
; CHECK-LABEL: @fcmp_oeq_select_same_consts(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[TMP1:%.*]] = fcmp oge double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[TMP1]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
%v4 = fcmp oeq double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; fcmp one (ordered not-equal) → xor (same as une for non-NaN)
;; ============================================================
define i1 @fcmp_one_select_same_consts(double %a, double %b) {
; CHECK-LABEL: @fcmp_one_select_same_consts(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp ult double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[V2]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
%v4 = fcmp one double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; fcmp ueq → xnor (same as oeq for non-NaN)
;; ============================================================
define i1 @fcmp_ueq_select_same_consts(double %a, double %b) {
; CHECK-LABEL: @fcmp_ueq_select_same_consts(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[TMP1:%.*]] = fcmp oge double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[TMP1]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
%v4 = fcmp ueq double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Swapped constants: (select C1, K1, K2) vs (select C2, K2, K1)
;; une with swapped → truth table 0b1001 → xnor
;; ============================================================
define i1 @fcmp_une_select_swapped_consts(double %a, double %b) {
; CHECK-LABEL: @fcmp_une_select_swapped_consts(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[TMP1:%.*]] = fcmp oge double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[TMP1]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double 1.000000e+00, double -1.000000e+00
%v4 = fcmp une double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Different constant pairs (not just -1/+1)
;; ============================================================
define i1 @fcmp_une_select_other_consts(double %a, double %b) {
; CHECK-LABEL: @fcmp_une_select_other_consts(
; CHECK-NEXT: [[V0:%.*]] = fcmp olt double [[B:%.*]], 5.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp olt double [[A:%.*]], 5.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[V2]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp olt double %b, 5.000000e+00
%v1 = select i1 %v0, double 4.200000e+01, double 1.337000e+02
%v2 = fcmp olt double %a, 5.000000e+00
%v3 = select i1 %v2, double 4.200000e+01, double 1.337000e+02
%v4 = fcmp une double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Float type (not just double)
;; ============================================================
define i1 @fcmp_une_select_float(float %a, float %b) {
; CHECK-LABEL: @fcmp_une_select_float(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult float [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp ult float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[V2]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult float %b, 0.000000e+00
%v1 = select i1 %v0, float -1.000000e+00, float 1.000000e+00
%v2 = fcmp ult float %a, 0.000000e+00
%v3 = select i1 %v2, float -1.000000e+00, float 1.000000e+00
%v4 = fcmp une float %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Relational predicate: olt → now folds via truth table
;; Truth table: 0b0100 → and(C1, not(C2))
;; ============================================================
define i1 @fcmp_olt_select(double %a, double %b) {
; CHECK-LABEL: @fcmp_olt_select(
; CHECK-NEXT: [[V2:%.*]] = fcmp ult double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V3:%.*]] = fcmp oge double [[A1:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = and i1 [[V2]], [[V3]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
%v4 = fcmp olt double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Relational predicate: ogt → truth table 0b0010
;; → and(not(C1), C2)
;; ============================================================
define i1 @fcmp_ogt_select(double %a, double %b) {
; CHECK-LABEL: @fcmp_ogt_select(
; CHECK-NEXT: [[V0:%.*]] = fcmp oge double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp ult double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V4:%.*]] = and i1 [[V0]], [[V2]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
%v4 = fcmp ogt double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Vector type
;; ============================================================
define <2 x i1> @fcmp_une_select_vec(<2 x double> %a, <2 x double> %b) {
; CHECK-LABEL: @fcmp_une_select_vec(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult <2 x double> [[B:%.*]], zeroinitializer
; CHECK-NEXT: [[V2:%.*]] = fcmp ult <2 x double> [[A:%.*]], zeroinitializer
; CHECK-NEXT: [[V4:%.*]] = xor <2 x i1> [[V0]], [[V2]]
; CHECK-NEXT: ret <2 x i1> [[V4]]
;
%v0 = fcmp ult <2 x double> %b, zeroinitializer
%v1 = select <2 x i1> %v0, <2 x double> <double -1.0, double -1.0>, <2 x double> <double 1.0, double 1.0>
%v2 = fcmp ult <2 x double> %a, zeroinitializer
%v3 = select <2 x i1> %v2, <2 x double> <double -1.0, double -1.0>, <2 x double> <double 1.0, double 1.0>
%v4 = fcmp une <2 x double> %v1, %v3
ret <2 x i1> %v4
}
;; ============================================================
;; Negative: vector constant folding can yield a mixed mask like
;; <i1 true, i1 false>, so the truth-table fold must bail out.
;; ============================================================
define <2 x i1> @fcmp_une_select_vec_mixed_mask_no_fold(<2 x i1> %c0, <2 x i1> %c1) {
; CHECK-LABEL: @fcmp_une_select_vec_mixed_mask_no_fold(
; CHECK-NEXT: [[S0:%.*]] = select <2 x i1> [[C0:%.*]], <2 x double> <double 1.000000e+00, double 2.000000e+00>, <2 x double> <double 3.000000e+00, double 4.000000e+00>
; CHECK-NEXT: [[S1:%.*]] = select <2 x i1> [[C1:%.*]], <2 x double> <double 1.000000e+00, double 9.000000e+00>, <2 x double> <double 8.000000e+00, double 4.000000e+00>
; CHECK-NEXT: [[R:%.*]] = fcmp une <2 x double> [[S0]], [[S1]]
; CHECK-NEXT: ret <2 x i1> [[R]]
%s0 = select <2 x i1> %c0,
<2 x double> <double 1.0, double 2.0>,
<2 x double> <double 3.0, double 4.0>
%s1 = select <2 x i1> %c1,
<2 x double> <double 1.0, double 9.0>,
<2 x double> <double 8.0, double 4.0>
%r = fcmp une <2 x double> %s0, %s1
ret <2 x i1> %r
}
;; ============================================================
;; Multi-use: une (xor) still folds — xor is single instruction
;; ============================================================
define i1 @fcmp_une_select_multi_use(double %a, double %b) {
; CHECK-LABEL: @fcmp_une_select_multi_use(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[V1:%.*]] = select i1 [[V0]], double -1.000000e+00, double 1.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp ult double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V3:%.*]] = select i1 [[V2]], double -1.000000e+00, double 1.000000e+00
; CHECK-NEXT: call void @use_double(double [[V1]])
; CHECK-NEXT: call void @use_double(double [[V3]])
; CHECK-NEXT: [[V4:%.*]] = xor i1 [[V0]], [[V2]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
call void @use_double(double %v1)
call void @use_double(double %v3)
%v4 = fcmp une double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Negative: multi-use + olt (needs 2 instructions, HasOneUse=false)
;; → createLogicFromTable returns nullptr
;; ============================================================
define i1 @fcmp_olt_select_multi_use_no_fold(double %a, double %b) {
; CHECK-LABEL: @fcmp_olt_select_multi_use_no_fold(
; CHECK-NEXT: [[V0:%.*]] = fcmp ult double [[B:%.*]], 0.000000e+00
; CHECK-NEXT: [[V1:%.*]] = select i1 [[V0]], double -1.000000e+00, double 1.000000e+00
; CHECK-NEXT: [[V2:%.*]] = fcmp ult double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[V3:%.*]] = select i1 [[V2]], double -1.000000e+00, double 1.000000e+00
; CHECK-NEXT: call void @use_double(double [[V1]])
; CHECK-NEXT: call void @use_double(double [[V3]])
; CHECK-NEXT: [[V4:%.*]] = fcmp olt double [[V1]], [[V3]]
; CHECK-NEXT: ret i1 [[V4]]
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -1.000000e+00, double 1.000000e+00
call void @use_double(double %v1)
call void @use_double(double %v3)
%v4 = fcmp olt double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Negative: constants are the same (K1 == K2)
;; Selects simplify to constant, fcmp une → false
;; ============================================================
define i1 @fcmp_une_select_same_val(double %a, double %b) {
; CHECK-LABEL: @fcmp_une_select_same_val(
; CHECK-NEXT: ret i1 false
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double 1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double 1.000000e+00, double 1.000000e+00
%v4 = fcmp une double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; Different constant pairs across selects
;; All 4 combinations yield une=true → constant true
;; ============================================================
define i1 @fcmp_une_select_diff_pairs(double %a, double %b) {
; CHECK-LABEL: @fcmp_une_select_diff_pairs(
; CHECK-NEXT: ret i1 true
;
%v0 = fcmp ult double %b, 0.000000e+00
%v1 = select i1 %v0, double -1.000000e+00, double 1.000000e+00
%v2 = fcmp ult double %a, 0.000000e+00
%v3 = select i1 %v2, double -2.000000e+00, double 3.000000e+00
%v4 = fcmp une double %v1, %v3
ret i1 %v4
}
;; ============================================================
;; icmp ne with select of integer constants → xor
;; Truth table: 0b0110
;; ============================================================
define i1 @icmp_ne_select_consts(i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_ne_select_consts(
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%s1 = icmp slt i32 %a, 0
%v1 = select i1 %s1, i32 -1, i32 1
%s2 = icmp slt i32 %b, 0
%v2 = select i1 %s2, i32 -1, i32 1
%r = icmp ne i32 %v1, %v2
ret i1 %r
}
;; ============================================================
;; icmp eq with select of integer constants → xnor
;; Truth table: 0b1001
;; ============================================================
define i1 @icmp_eq_select_consts(i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_eq_select_consts(
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[R]]
;
%s1 = icmp slt i32 %a, 0
%v1 = select i1 %s1, i32 -1, i32 1
%s2 = icmp slt i32 %b, 0
%v2 = select i1 %s2, i32 -1, i32 1
%r = icmp eq i32 %v1, %v2
ret i1 %r
}
;; ============================================================
;; icmp slt with select of integer constants
;; Truth table: 0b0100 → and(C1, not(C2))
;; ============================================================
define i1 @icmp_slt_select_consts(i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_slt_select_consts(
; CHECK-NEXT: [[S1_INV:%.*]] = icmp slt i32 [[A:%.*]], 0
; CHECK-NEXT: [[S2_INV:%.*]] = icmp sgt i32 [[B:%.*]], -1
; CHECK-NEXT: [[R:%.*]] = select i1 [[S1_INV]], i1 [[S2_INV]], i1 false
; CHECK-NEXT: ret i1 [[R]]
;
%s1 = icmp slt i32 %a, 0
%v1 = select i1 %s1, i32 -1, i32 1
%s2 = icmp slt i32 %b, 0
%v2 = select i1 %s2, i32 -1, i32 1
%r = icmp slt i32 %v1, %v2
ret i1 %r
}
;; ============================================================
;; icmp with swapped integer constants
;; icmp ne (select C1, -1, 1), (select C2, 1, -1)
;; Truth table: 0b1001 → xnor
;; ============================================================
define i1 @icmp_ne_select_swapped_consts(i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_ne_select_swapped_consts(
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[R]]
;
%s1 = icmp slt i32 %a, 0
%v1 = select i1 %s1, i32 -1, i32 1
%s2 = icmp slt i32 %b, 0
%v2 = select i1 %s2, i32 1, i32 -1
%r = icmp ne i32 %v1, %v2
ret i1 %r
}
;; ============================================================
;; Negative: vector condition should not fold via truth table.
;; ConstantFoldCompareInstOperands may yield a mixed mask like
;; <i1 true, i1 false>, so we must bail out.
;; ============================================================
define <2 x i1> @icmp_eq_select_vec_cond_no_fold(<2 x i1> %c1, <2 x i1> %c2) {
; CHECK-LABEL: @icmp_eq_select_vec_cond_no_fold(
; CHECK-NEXT: [[S1:%.*]] = select <2 x i1> [[C1:%.*]], <2 x i32> <i32 1, i32 2>, <2 x i32> <i32 3, i32 4>
; CHECK-NEXT: [[S2:%.*]] = select <2 x i1> [[C2:%.*]], <2 x i32> <i32 1, i32 9>, <2 x i32> <i32 8, i32 4>
; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i32> [[S1]], [[S2]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%s1 = select <2 x i1> %c1,
<2 x i32> <i32 1, i32 2>,
<2 x i32> <i32 3, i32 4>
%s2 = select <2 x i1> %c2,
<2 x i32> <i32 1, i32 9>,
<2 x i32> <i32 8, i32 4>
%r = icmp eq <2 x i32> %s1, %s2
ret <2 x i1> %r
}
;; ============================================================
;; Negative: mixed vector/scalar select conditions should not
;; fold via truth table.
;; ============================================================
define <2 x i1> @icmp_eq_mixed_cond_no_fold(<2 x i1> %c1, i1 %c2) {
; CHECK-LABEL: @icmp_eq_mixed_cond_no_fold(
; CHECK-NEXT: [[S1:%.*]] = select <2 x i1> [[C1:%.*]], <2 x i32> <i32 1, i32 2>, <2 x i32> <i32 3, i32 4>
; CHECK-NEXT: [[S2:%.*]] = select i1 [[C2:%.*]], <2 x i32> <i32 1, i32 9>, <2 x i32> <i32 8, i32 4>
; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i32> [[S1]], [[S2]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%s1 = select <2 x i1> %c1,
<2 x i32> <i32 1, i32 2>,
<2 x i32> <i32 3, i32 4>
%s2 = select i1 %c2,
<2 x i32> <i32 1, i32 9>,
<2 x i32> <i32 8, i32 4>
%r = icmp eq <2 x i32> %s1, %s2
ret <2 x i1> %r
}