[llvm] [InstCombine] Fold cmp of select-of-constants via truth table (PR #186591)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 18 10:07:54 PDT 2026
================
@@ -0,0 +1,362 @@
+; 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) {
----------------
FYLGQ wrote:
Updated as suggested:
reverted the unrelated formatting changes in InstCombineInternal.h
added a negative vector test for mixed masks such as <i1 true, i1 false>
updated the PR title/description
I also noticed that the current .cpp diff contains some changes that I do not recall intentionally deleting. I am double-checking that no unrelated changes were accidentally mixed into this PR. If you spot any out-of-scope parts there, please let me know and I will clean them up.
https://github.com/llvm/llvm-project/pull/186591
More information about the llvm-commits
mailing list