[llvm] [InstCombine] Try optimizing with knownbits which determined from Cond (PR #91762)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 13 15:51:38 PDT 2024
https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/91762
>From fb0bf835cbeefaf329268042d838ce750599e425 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Tue, 7 May 2024 06:00:04 +0900
Subject: [PATCH 1/7] [NFC] [InstCombine] Modify and Added tests for
select-of-bittest
Tests that begin with n in select-of-bittest are negative tests.
However, n5 test is different from the intent of the test because
bits in %t and %t2 are the same. This is probably a mistake,
so corrected it.
Also added tests for cases where the and/or/xor might be optimized
if it is placed in the cond and truval of selectInst.
proof : https://alive2.llvm.org/ce/z/KJbbbp
---
.../InstCombine/select-of-bittest.ll | 439 +++++++++++++-
llvm/test/Transforms/InstCombine/select.ll | 537 ++++++++++++++++--
2 files changed, 911 insertions(+), 65 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/select-of-bittest.ll b/llvm/test/Transforms/InstCombine/select-of-bittest.ll
index e3eb76de459e2..64cde528599b1 100644
--- a/llvm/test/Transforms/InstCombine/select-of-bittest.ll
+++ b/llvm/test/Transforms/InstCombine/select-of-bittest.ll
@@ -3,7 +3,440 @@
; https://bugs.llvm.org/show_bug.cgi?id=36950
-; These all should be just and+icmp, there should be no select.
+; ====================== AND =======================
+define i8 @src_and_bit(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_and_bit(
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], 3
+; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 2
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], 2
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 [[AND1]], i8 1
+; CHECK-NEXT: ret i8 [[COND]]
+;
+ %and = and i8 %x, 3
+ %and1 = and i8 %x, 2
+ %and2 = and i8 %and, %x
+ %cmp = icmp eq i8 %and2, 2
+ %cond = select i1 %cmp, i8 %and1, i8 1
+ ret i8 %cond
+}
+
+define <2 x i8> @src_and_bit_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_and_bit_vec(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 2, i8 2>
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %x, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 2, i8 2>
+ %and2 = and <2 x i8> %and, %x
+ %cmp = icmp eq <2 x i8> %and2, <i8 2, i8 2>
+ %cond = select <2 x i1> %cmp, <2 x i8> %and1, <2 x i8><i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_and_bit_vec_poison(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_and_bit_vec_poison(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %x, <i8 poison, i8 3>
+ %and1 = and <2 x i8> %x, <i8 poison, i8 2>
+ %and2 = and <2 x i8> %and, %x
+ %cmp = icmp eq <2 x i8> %and2, <i8 2, i8 2>
+ %cond = select <2 x i1> %cmp, <2 x i8> %and1, <2 x i8><i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_and_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_and_bit_vec_poison2(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %x, <i8 poison, i8 3>
+ %and1 = and <2 x i8> %x, <i8 poison, i8 2>
+ %and2 = and <2 x i8> %and, %x
+ %cmp = icmp eq <2 x i8> %and2, <i8 2, i8 2>
+ %cond = select <2 x i1> %cmp, <2 x i8> %and1, <2 x i8><i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define i8 @src_and_bit_ne(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_and_bit_ne(
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], 3
+; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 2
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[AND]], 2
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 [[AND1]], i8 1
+; CHECK-NEXT: ret i8 [[COND]]
+;
+ %and = and i8 %x, 3
+ %and1 = and i8 %x, 2
+ %and2 = and i8 %and, %x
+ %cmp = icmp ne i8 %and2, 2
+ %cond = select i1 %cmp, i8 1, i8 %and1
+ ret i8 %cond
+}
+
+define <2 x i8> @src_and_bit_vec_ne(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_and_bit_vec_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 2, i8 2>
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %x, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 2, i8 2>
+ %and2 = and <2 x i8> %and, %x
+ %cmp = icmp ne <2 x i8> %and2, <i8 2, i8 2>
+ %cond = select <2 x i1> %cmp, <2 x i8><i8 1, i8 1>, <2 x i8> %and1
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_and_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_and_bit_vec_poison_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %x, <i8 poison, i8 3>
+ %and1 = and <2 x i8> %x, <i8 poison, i8 2>
+ %and2 = and <2 x i8> %and, %x
+ %cmp = icmp ne <2 x i8> %and2, <i8 2, i8 2>
+ %cond = select <2 x i1> %cmp, <2 x i8><i8 1, i8 1>, <2 x i8> %and1
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_and_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_and_bit_vec_poison2_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %x, <i8 poison, i8 3>
+ %and1 = and <2 x i8> %x, <i8 poison, i8 2>
+ %and2 = and <2 x i8> %and, %x
+ %cmp = icmp ne <2 x i8> %and2, <i8 2, i8 2>
+ %cond = select <2 x i1> %cmp, <2 x i8><i8 1, i8 1>, <2 x i8> %and1
+ ret <2 x i8> %cond
+}
+
+; ====================== OR =======================
+define i8 @src_or_bit(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @src_or_bit(
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], 3
+; CHECK-NEXT: [[AND1:%.*]] = shl i8 [[Y:%.*]], 2
+; CHECK-NEXT: [[SHL:%.*]] = and i8 [[AND1]], 12
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 3
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 [[OR2]], i8 1
+; CHECK-NEXT: ret i8 [[COND]]
+;
+ %and = and i8 %z, 3
+ %and1 = shl i8 %y, 2
+ %shl = and i8 %and1, 12
+ %or = or i8 %shl, %x
+ %cmp = icmp eq i8 %or, 3
+ %or2 = or i8 %and, %x
+ %cond = select i1 %cmp, i8 %or2, i8 1
+ ret i8 %cond
+}
+
+define <2 x i8> @src_or_bit_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @src_or_bit_vec(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 2>
+; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 12>
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
+; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %z, <i8 3, i8 3>
+ %and1 = shl <2 x i8> %y, <i8 2, i8 2>
+ %shl = and <2 x i8> %and1, <i8 12, i8 12>
+ %or = or <2 x i8> %shl, %x
+ %cmp = icmp eq <2 x i8> %or, <i8 3, i8 3>
+ %or2 = or <2 x i8> %and, %x
+ %cond = select <2x i1> %cmp, <2 x i8> %or2, <2 x i8> <i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_bit_vec_poison(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @src_or_bit_vec_poison(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 poison>
+; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 poison>
+; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 poison>
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
+; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %z, <i8 3, i8 poison>
+ %and1 = shl <2 x i8> %y, <i8 2, i8 poison>
+ %shl = and <2 x i8> %and1, <i8 12, i8 poison>
+ %or = or <2 x i8> %shl, %x
+ %cmp = icmp eq <2 x i8> %or, <i8 3, i8 3>
+ %or2 = or <2 x i8> %and, %x
+ %cond = select <2 x i1> %cmp, <2 x i8> %or2, <2 x i8> <i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @src_or_bit_vec_poison2(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 poison, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 poison, i8 2>
+; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 poison, i8 12>
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
+; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %z, <i8 poison, i8 3>
+ %and1 = shl <2 x i8> %y, <i8 poison, i8 2>
+ %shl = and <2 x i8> %and1, <i8 poison, i8 12>
+ %or = or <2 x i8> %shl, %x
+ %cmp = icmp eq <2 x i8> %or, <i8 3, i8 3>
+ %or2 = or <2 x i8> %and, %x
+ %cond = select <2 x i1> %cmp, <2 x i8> %or2, <2 x i8> <i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define i8 @src_or_bit_ne(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @src_or_bit_ne(
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], 3
+; CHECK-NEXT: [[AND1:%.*]] = shl i8 [[Y:%.*]], 2
+; CHECK-NEXT: [[SHL:%.*]] = and i8 [[AND1]], 12
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[OR]], 3
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 [[OR2]], i8 1
+; CHECK-NEXT: ret i8 [[COND]]
+;
+ %and = and i8 %z, 3
+ %and1 = shl i8 %y, 2
+ %shl = and i8 %and1, 12
+ %or = or i8 %shl, %x
+ %cmp = icmp ne i8 %or, 3
+ %or2 = or i8 %and, %x
+ %cond = select i1 %cmp, i8 1, i8 %or2
+ ret i8 %cond
+}
+
+define <2 x i8> @src_or_bit_vec_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @src_or_bit_vec_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 2>
+; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 12>
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
+; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %z, <i8 3, i8 3>
+ %and1 = shl <2 x i8> %y, <i8 2, i8 2>
+ %shl = and <2 x i8> %and1, <i8 12, i8 12>
+ %or = or <2 x i8> %shl, %x
+ %cmp = icmp ne <2 x i8> %or, <i8 3, i8 3>
+ %or2 = or <2 x i8> %and, %x
+ %cond = select <2x i1> %cmp, <2 x i8> <i8 1, i8 1>, <2 x i8> %or2
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @src_or_bit_vec_poison_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 poison>
+; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 poison>
+; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 poison>
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
+; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %z, <i8 3, i8 poison>
+ %and1 = shl <2 x i8> %y, <i8 2, i8 poison>
+ %shl = and <2 x i8> %and1, <i8 12, i8 poison>
+ %or = or <2 x i8> %shl, %x
+ %cmp = icmp ne <2 x i8> %or, <i8 3, i8 3>
+ %or2 = or <2 x i8> %and, %x
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 1, i8 1>, <2 x i8> %or2
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
+; CHECK-LABEL: @src_or_bit_vec_poison2_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 poison, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 poison, i8 2>
+; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 poison, i8 12>
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
+; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %z, <i8 poison, i8 3>
+ %and1 = shl <2 x i8> %y, <i8 poison, i8 2>
+ %shl = and <2 x i8> %and1, <i8 poison, i8 12>
+ %or = or <2 x i8> %shl, %x
+ %cmp = icmp ne <2 x i8> %or, <i8 3, i8 3>
+ %or2 = or <2 x i8> %and, %x
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 1, i8 1>, <2 x i8> %or2
+ ret <2 x i8> %cond
+}
+
+; ====================== XOR =======================
+define i8 @src_xor_bit(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_xor_bit(
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y:%.*]], 12
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[XOR]], 3
+; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 3
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 [[AND1]], i8 1
+; CHECK-NEXT: ret i8 [[COND]]
+;
+ %and = and i8 %y, 12
+ %xor = xor i8 %and, %x
+ %cmp = icmp eq i8 %xor, 3
+ %and1 = and i8 %x, 3
+ %cond = select i1 %cmp, i8 %and1, i8 1
+ ret i8 %cond
+}
+
+define <2 x i8> @src_xor_bit_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_xor_bit_vec(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 12, i8 12>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %y, <i8 12, i8 12>
+ %xor = xor <2 x i8> %and, %x
+ %cmp = icmp eq <2 x i8> %xor, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 3, i8 3>
+ %cond = select <2 x i1> %cmp, <2 x i8> %and1, <2 x i8> <i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_xor_bit_vec_poison(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_xor_bit_vec_poison(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 3>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %y, <i8 poison, i8 12>
+ %xor = xor <2 x i8> %and, %x
+ %cmp = icmp eq <2 x i8> %xor, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 poison, i8 3>
+ %cond = select <2 x i1> %cmp, <2 x i8> %and1, <2 x i8> <i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_xor_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_xor_bit_vec_poison2(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %y, <i8 poison, i8 12>
+ %xor = xor <2 x i8> %and, %x
+ %cmp = icmp eq <2 x i8> %xor, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 3, i8 3>
+ %cond = select <2 x i1> %cmp, <2 x i8> %and1, <2 x i8> <i8 1, i8 1>
+ ret <2 x i8> %cond
+}
+
+define i8 @src_xor_bit_ne(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_xor_bit_ne(
+; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y:%.*]], 12
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[XOR]], 3
+; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 3
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 [[AND1]], i8 1
+; CHECK-NEXT: ret i8 [[COND]]
+;
+ %and = and i8 %y, 12
+ %xor = xor i8 %and, %x
+ %cmp = icmp ne i8 %xor, 3
+ %and1 = and i8 %x, 3
+ %cond = select i1 %cmp, i8 1, i8 %and1
+ ret i8 %cond
+}
+
+define <2 x i8> @src_xor_bit_vec_ne(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_xor_bit_vec_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 12, i8 12>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %y, <i8 12, i8 12>
+ %xor = xor <2 x i8> %and, %x
+ %cmp = icmp ne <2 x i8> %xor, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 3, i8 3>
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 1, i8 1>, <2 x i8> %and1
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_xor_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_xor_bit_vec_poison_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 3>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %y, <i8 poison, i8 12>
+ %xor = xor <2 x i8> %and, %x
+ %cmp = icmp ne <2 x i8> %xor, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 poison, i8 3>
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 1, i8 1>, <2 x i8> %and1
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_xor_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_xor_bit_vec_poison2_ne(
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
+; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+ %and = and <2 x i8> %y, <i8 poison, i8 12>
+ %xor = xor <2 x i8> %and, %x
+ %cmp = icmp ne <2 x i8> %xor, <i8 3, i8 3>
+ %and1 = and <2 x i8> %x, <i8 3, i8 3>
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 1, i8 1>, <2 x i8> %and1
+ ret <2 x i8> %cond
+}
define i32 @and_lshr_and(i32 %arg) {
; CHECK-LABEL: @and_lshr_and(
@@ -590,13 +1023,13 @@ define i32 @n5(i32 %arg) {
; CHECK-LABEL: @n5(
; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 2
; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[T]], 0
-; CHECK-NEXT: [[T2:%.*]] = and i32 [[ARG]], 2
+; CHECK-NEXT: [[T2:%.*]] = and i32 [[ARG]], 3
; CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 [[T2]], i32 1
; CHECK-NEXT: ret i32 [[T3]]
;
%t = and i32 %arg, 2
%t1 = icmp eq i32 %t, 0
- %t2 = and i32 %arg, 2 ; 2 instead of 1
+ %t2 = and i32 %arg, 3 ; 3 instead of 2
%t3 = select i1 %t1, i32 %t2, i32 1
ret i32 %t3
}
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index b37e9175b26a5..ea37792b5777f 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3759,6 +3759,195 @@ exit:
}
; Select icmp and/or/xor
+; X|Y==-1?X^Y:-1
+define i32 @src_or_disjoint_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 -1
+; CHECK-NEXT: ret i32 [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint i32 %x, %y
+ %cmp = icmp eq i32 %or.disjoint, -1
+ %xor = xor i32 %x, %y
+ %cond = select i1 %cmp, i32 %xor, i32 -1
+ ret i32 %cond
+}
+
+define i32 @src_or_disjoint_xor_comm(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_comm(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 -1
+; CHECK-NEXT: ret i32 [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint i32 %x, %y
+ %cmp = icmp eq i32 %or.disjoint, -1
+ %xor = xor i32 %x, %y
+ %cond = select i1 %cmp, i32 %xor, i32 -1
+ ret i32 %cond
+}
+
+define i32 @src_or_disjoint_xor_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_ne(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 -1
+; CHECK-NEXT: ret i32 [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint i32 %x, %y
+ %cmp = icmp ne i32 %or.disjoint, -1
+ %xor = xor i32 %x, %y
+ %cond = select i1 %cmp, i32 -1, i32 %xor
+ ret i32 %cond
+}
+
+define i32 @src_or_disjoint_xor_ne_comm(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_ne_comm(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 -1
+; CHECK-NEXT: ret i32 [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint i32 %y, %x
+ %cmp = icmp ne i32 %or.disjoint, -1
+ %xor = xor i32 %y, %x
+ %cond = select i1 %cmp, i32 -1, i32 %xor
+ ret i32 %cond
+}
+
+define <2 x i8> @src_or_disjoint_xor_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint <2 x i8> %x, %y
+ %cmp = icmp eq <2 x i8> %or.disjoint, <i8 -1, i8 -1>
+ %xor = xor <2 x i8> %x, %y
+ %cond = select <2 x i1> %cmp, <2 x i8> %xor, <2 x i8> <i8 -1, i8 -1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_disjoint_xor_comm_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_comm_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint <2 x i8> %x, %y
+ %cmp = icmp eq <2 x i8> %or.disjoint, <i8 -1, i8 -1>
+ %xor = xor <2 x i8> %x, %y
+ %cond = select <2 x i1> %cmp, <2 x i8> %xor, <2 x i8> <i8 -1, i8 -1>
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_disjoint_xor_ne_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_ne_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint <2 x i8> %x, %y
+ %cmp = icmp ne <2 x i8> %or.disjoint, <i8 -1, i8 -1>
+ %xor = xor <2 x i8> %x, %y
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 -1, i8 -1>, <2 x i8> %xor
+ ret <2 x i8> %cond
+}
+
+define <2 x i8> @src_or_disjoint_xor_ne_comm_vec(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_ne_comm_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
+; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
+; CHECK-NEXT: ret <2 x i8> [[COND]]
+;
+entry:
+ %or.disjoint = or disjoint <2 x i8> %y, %x
+ %cmp = icmp ne <2 x i8> %or.disjoint, <i8 -1, i8 -1>
+ %xor = xor <2 x i8> %y, %x
+ %cond = select <2 x i1> %cmp, <2 x i8> <i8 -1, i8 -1>, <2 x i8> %xor
+ ret <2 x i8> %cond
+}
+
+define i32 @src_or_disjoint_xor_poison(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_poison(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 poison
+;
+entry:
+ %or.disjoint = or disjoint i32 %x, %y
+ %cmp = icmp eq i32 %or.disjoint, poison
+ %xor = xor i32 %x, %y
+ %cond = select i1 %cmp, i32 %xor, i32 poison
+ ret i32 %cond
+}
+
+define i32 @src_or_disjoint_xor_comm_poison(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_comm_poison(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 poison
+;
+entry:
+ %or.disjoint = or disjoint i32 %x, %y
+ %cmp = icmp eq i32 %or.disjoint, poison
+ %xor = xor i32 %x, %y
+ %cond = select i1 %cmp, i32 %xor, i32 poison
+ ret i32 %cond
+}
+
+define i32 @src_or_disjoint_xor_ne_poison(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_ne_poison(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 poison
+;
+entry:
+ %or.disjoint = or disjoint i32 %x, %y
+ %cmp = icmp ne i32 %or.disjoint, poison
+ %xor = xor i32 %x, %y
+ %cond = select i1 %cmp, i32 poison, i32 %xor
+ ret i32 %cond
+}
+
+define i32 @src_or_disjoint_xor_ne_comm_poison(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_disjoint_xor_ne_comm_poison(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i32 poison
+;
+entry:
+ %or.disjoint = or disjoint i32 %y, %x
+ %cmp = icmp ne i32 %or.disjoint, poison
+ %xor = xor i32 %y, %x
+ %cond = select i1 %cmp, i32 poison, i32 %xor
+ ret i32 %cond
+}
+
; https://alive2.llvm.org/ce/z/QXQDwF
; X&Y==C?X|Y:X^Y, X&Y==C?X^Y:X|Y
; TODO: X&Y==0 could imply no_common_bit to TrueValue
@@ -3781,6 +3970,23 @@ entry:
ret i32 %cond
}
+define i32 @src_and_ne_0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_and_ne_0_xor_or(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %and = and i32 %y, %x
+ %cmp = icmp ne i32 %and, 0
+ %or = or i32 %y, %x
+ %xor = xor i32 %y, %x
+ %cond = select i1 %cmp, i32 %xor, i32 %or
+ ret i32 %cond
+}
+
; TODO: X&Y==0 could imply no_common_bit to TrueValue
define i32 @src_and_eq_0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_0_xor_or(
@@ -3801,6 +4007,23 @@ entry:
ret i32 %cond
}
+define i32 @src_and_ne_0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_and_ne_0_or_xor(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %and = and i32 %y, %x
+ %cmp = icmp ne i32 %and, 0
+ %xor = xor i32 %y, %x
+ %or = or i32 %y, %x
+ %cond = select i1 %cmp, i32 %or, i32 %xor
+ ret i32 %cond
+}
+
; TODO: X&Y==-1 could imply all_common_bit to TrueValue
define i32 @src_and_eq_neg1_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_neg1_or_xor(
@@ -3821,6 +4044,23 @@ entry:
ret i32 %cond
}
+define i32 @src_and_ne_neg1_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_and_ne_neg1_xor_or(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], -1
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %and = and i32 %y, %x
+ %cmp = icmp ne i32 %and, -1
+ %or = or i32 %y, %x
+ %xor = xor i32 %y, %x
+ %cond = select i1 %cmp, i32 %xor, i32 %or
+ ret i32 %cond
+}
+
; TODO: X&Y==-1 could imply all_common_bit to TrueValue
define i32 @src_and_eq_neg1_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_neg1_xor_or(
@@ -3841,6 +4081,23 @@ entry:
ret i32 %cond
}
+define i32 @src_and_ne_neg1_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_and_ne_neg1_or_xor(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %and = and i32 %y, %x
+ %cmp = icmp ne i32 %and, -1
+ %xor = xor i32 %y, %x
+ %or = or i32 %y, %x
+ %cond = select i1 %cmp, i32 %or, i32 %xor
+ ret i32 %cond
+}
+
define i32 @src_and_eq_C_or_xororC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_and_eq_C_or_xororC(
; CHECK-NEXT: entry:
@@ -3956,6 +4213,23 @@ entry:
ret i32 %cond
}
+define i32 @src_or_ne_0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_ne_0_xor_and(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %y, %x
+ %cmp = icmp ne i32 %or, 0
+ %and = and i32 %y, %x
+ %xor = xor i32 %y, %x
+ %cond = select i1 %cmp, i32 %xor, i32 %and
+ ret i32 %cond
+}
+
; TODO: X|Y==0 could imply no_common_bit to TrueValue
define i32 @src_or_eq_0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_0_xor_and(
@@ -3976,6 +4250,23 @@ entry:
ret i32 %cond
}
+define i32 @src_or_ne_0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_or_ne_0_and_xor(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[AND]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %y, %x
+ %cmp = icmp ne i32 %or, 0
+ %xor = xor i32 %y, %x
+ %and = and i32 %y, %x
+ %cond = select i1 %cmp, i32 %and, i32 %xor
+ ret i32 %cond
+}
+
define i32 @src_or_eq_neg1_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_neg1_and_xor(
; CHECK-NEXT: entry:
@@ -4189,6 +4480,190 @@ entry:
ret i32 %cond
}
+define i32 @src_select_or_eq0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_eq0_or_xor(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 0, i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+
+define i32 @src_select_or_ne0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_ne0_xor_or(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 0, i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %x, %y
+ %or0 = icmp ne i32 %or, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %xor, i32 %or
+ ret i32 %cond
+}
+
+define i32 @src_select_or_eq0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_eq0_and_or(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %or
+ ret i32 %cond
+}
+
+define i32 @src_select_or_ne0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_ne0_or_and(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 [[AND]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %x, %y
+ %or0 = icmp ne i32 %or, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %or0, i32 %or, i32 %and
+ ret i32 %cond
+}
+
+define i32 @src_select_xor_eq0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_eq0_and_xor(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %xor0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+
+define i32 @src_select_xor_ne0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_ne0_xor_and(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %xor = xor i32 %x, %y
+ %xor0 = icmp ne i32 %xor, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %xor0, i32 %xor, i32 %and
+ ret i32 %cond
+}
+
+define i32 @src_select_xor_eq0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_eq0_or_xor(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %xor0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+
+define i32 @src_select_xor_ne0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_ne0_xor_or(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %xor = xor i32 %x, %y
+ %xor0 = icmp ne i32 %xor, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %xor0, i32 %xor, i32 %or
+ ret i32 %cond
+}
+
+define i32 @src_select_or_eq0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_eq0_xor_or(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[XOR]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %xor, i32 %or
+ ret i32 %cond
+}
+
+define i32 @src_select_or_ne0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_ne0_or_xor(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 [[XOR]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %or = or i32 %x, %y
+ %or0 = icmp ne i32 %or, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+
+define i32 @src_select_xor_max_negative_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_max_negative_int(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, -1
+ %and = and i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %xor0, i32 %and, i32 %or
+ ret i32 %cond
+}
+
+define i32 @src_select_xor_max_negative_int_ne(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_max_negative_int_ne(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[AND]], i32 [[OR]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %xor = xor i32 %x, %y
+ %xor0 = icmp ne i32 %xor, -1
+ %and = and i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %xor0, i32 %or, i32 %and
+ ret i32 %cond
+}
+
; Select icmp and/or/xor
; NO TRANSFORMED - select condition is compare with not 0
define i32 @src_select_and_min_positive_int(i32 %x, i32 %y) {
@@ -4361,23 +4836,6 @@ define i32 @src_select_xor_min_negative_int(i32 %x, i32 %y) {
ret i32 %cond
}
-define i32 @src_select_xor_max_negative_int(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_select_xor_max_negative_int(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], -1
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
-;
- %xor = xor i32 %x, %y
- %xor0 = icmp eq i32 %xor, -1
- %and = and i32 %x, %y
- %or = or i32 %x, %y
- %cond = select i1 %xor0, i32 %and, i32 %or
- ret i32 %cond
-}
-
; Select icmp and/or/xor
; https://alive2.llvm.org/ce/z/BVgrJ-
; NO TRANSFORMED - not supported
@@ -4456,51 +4914,6 @@ define i32 @src_no_trans_select_or_eq0_or_and(i32 %x, i32 %y) {
ret i32 %cond
}
-define i32 @src_no_trans_select_or_eq0_or_xor(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_no_trans_select_or_eq0_or_xor(
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 0, i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
-;
- %or = or i32 %x, %y
- %or0 = icmp eq i32 %or, 0
- %xor = xor i32 %x, %y
- %cond = select i1 %or0, i32 %or, i32 %xor
- ret i32 %cond
-}
-
-define i32 @src_no_trans_select_or_eq0_and_or(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_no_trans_select_or_eq0_and_or(
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
-;
- %or = or i32 %x, %y
- %or0 = icmp eq i32 %or, 0
- %and = and i32 %x, %y
- %cond = select i1 %or0, i32 %and, i32 %or
- ret i32 %cond
-}
-
-define i32 @src_no_trans_select_or_eq0_xor_or(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_no_trans_select_or_eq0_xor_or(
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
-;
- %or = or i32 %x, %y
- %or0 = icmp eq i32 %or, 0
- %xor = xor i32 %x, %y
- %cond = select i1 %or0, i32 %xor, i32 %or
- ret i32 %cond
-}
-
define i32 @src_no_trans_select_and_ne0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_no_trans_select_and_ne0_xor_or(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
>From 6e330f2f582b99f3d9e4fbc45cc3a13b41887deb Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Tue, 7 May 2024 06:01:11 +0900
Subject: [PATCH 2/7] [InstCombine] Export computeKnownBitsFromCond in
ValueTracking
to use `Cond` in `SelectInst` for compute KnownBits.
---
llvm/include/llvm/Analysis/ValueTracking.h | 4 ++++
llvm/lib/Analysis/ValueTracking.cpp | 6 +++---
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index e577d0cc7ad41..57fa4f29d5eff 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -94,6 +94,10 @@ void computeKnownBitsFromRangeMetadata(const MDNode &Ranges, KnownBits &Known);
void computeKnownBitsFromContext(const Value *V, KnownBits &Known,
unsigned Depth, const SimplifyQuery &Q);
+void computeKnownBitsFromCond(const Value *V, Value *Cond, KnownBits &Known,
+ unsigned Depth, const SimplifyQuery &SQ,
+ bool Invert);
+
/// Using KnownBits LHS/RHS produce the known bits for logic op (and/xor/or).
KnownBits analyzeKnownBitsFromAndXorOr(const Operator *I,
const KnownBits &KnownLHS,
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8126d2a1acc27..085e4a81d17ee 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -747,9 +747,9 @@ static void computeKnownBitsFromICmpCond(const Value *V, ICmpInst *Cmp,
computeKnownBitsFromCmp(V, Pred, LHS, RHS, Known, SQ);
}
-static void computeKnownBitsFromCond(const Value *V, Value *Cond,
- KnownBits &Known, unsigned Depth,
- const SimplifyQuery &SQ, bool Invert) {
+void llvm::computeKnownBitsFromCond(const Value *V, Value *Cond,
+ KnownBits &Known, unsigned Depth,
+ const SimplifyQuery &SQ, bool Invert) {
Value *A, *B;
if (Depth < MaxAnalysisRecursionDepth &&
match(Cond, m_LogicalOp(m_Value(A), m_Value(B)))) {
>From 806bdbfec6c874ce9351d782ea7cb71f50d63d42 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Tue, 7 May 2024 06:04:30 +0900
Subject: [PATCH 3/7] [InstCombine] Try optimizing with knownbits which
determined from SelectInst Cond
ICmpInst of SelectInst is not included in the calculation of KnownBits
so we are missing the opportunity to optimize the Value of the True or
False Condition via ICmpInst with KnownBits.
Consider:
%or = or i32 %x, %y
%or0 = icmp eq i32 %or, 0
%and = and i32 %x, %y
%cond = select i1 %or0, i32 %and, i32 %or
ret i32 %cond
Expect:
%or = or i32 %x, %y
ret i32 %or
We could know what bit was enabled for %x, %y by ICmpInst in SelectInst.
This patch is an implementation that calculates the known bits over ICmp
and optimizes them where possible.
Proof : https://alive2.llvm.org/ce/z/CT7WFW
---
.../Transforms/InstCombine/InstCombiner.h | 7 +
.../InstCombine/InstCombineSelect.cpp | 156 ++++++++++++++++++
2 files changed, 163 insertions(+)
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 855d1aeddfaee..f81150b7b31f6 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -438,6 +438,13 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
return llvm::computeKnownBits(V, Depth, SQ.getWithInstruction(CxtI));
}
+ void computeKnownBitsFromCond(const Value *V, ICmpInst *Cmp, KnownBits &Known,
+ unsigned Depth, const Instruction *CxtI,
+ bool Invert) const {
+ llvm::computeKnownBitsFromCond(V, Cmp, Known, Depth,
+ SQ.getWithInstruction(CxtI), Invert);
+ }
+
bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero = false,
unsigned Depth = 0,
const Instruction *CxtI = nullptr) {
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7d26807544d7e..038e10c4c5202 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1809,6 +1809,158 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
return nullptr;
}
+// ICmpInst of SelectInst is not included in the calculation of KnownBits
+// so we are missing the opportunity to optimize the Value of the True or
+// False Condition via ICmpInst with KnownBits.
+//
+// Consider:
+// %or = or i32 %x, %y
+// %or0 = icmp eq i32 %or, 0
+// %and = and i32 %x, %y
+// %cond = select i1 %or0, i32 %and, i32 %or
+// ret i32 %cond
+//
+// Expect:
+// %or = or i32 %x, %y
+// ret i32 %or
+//
+// We could know what bit was enabled for %x, %y by ICmpInst in SelectInst.
+static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
+ Value *CmpLHS, Value *CmpRHS,
+ Value *TVal, Value *FVal,
+ InstCombinerImpl &IC) {
+ Value *X, *Y;
+ const APInt *C;
+
+ if (!((match(CmpLHS, m_BinOp(m_Value(X), m_Value(Y))) &&
+ match(CmpRHS, m_APInt(C))) &&
+ (match(TVal, m_c_BinOp(m_Specific(X), m_Value())) ||
+ match(TVal, m_c_BinOp(m_Specific(Y), m_Value())))))
+ return nullptr;
+
+ enum SpecialKnownBits {
+ NothingSpecial = 0,
+ NoCommonBits = 1 << 1,
+ AllCommonBits = 1 << 2,
+ AllBitsEnabled = 1 << 3,
+ };
+
+ // We cannot know exactly what bits is known in X Y.
+ // Instead, we just know what relationship exist for.
+ auto isSpecialKnownBitsFor = [&](const Instruction *CmpLHS,
+ const APInt *CmpRHS) -> unsigned {
+ unsigned Opc = CmpLHS->getOpcode();
+ if (Opc == Instruction::And) {
+ if (CmpRHS->isZero())
+ return NoCommonBits;
+ } else if (Opc == Instruction::Xor) {
+ if (CmpRHS->isAllOnes())
+ return NoCommonBits | AllBitsEnabled;
+ if (CmpRHS->isZero())
+ return AllCommonBits;
+ }
+
+ return NothingSpecial;
+ };
+
+ auto hasOperandAt = [&](Instruction *I, Value *Op) -> int {
+ for (unsigned Idx = 0; Idx < I->getNumOperands(); Idx++) {
+ if (I->getOperand(Idx) == Op)
+ return Idx + 1;
+ }
+ return 0;
+ };
+
+ Type *TValTy = TVal->getType();
+ unsigned BitWidth = TVal->getType()->getScalarSizeInBits();
+ auto TValBop = cast<BinaryOperator>(TVal);
+ auto CmpLHSBop = cast<BinaryOperator>(CmpLHS);
+ unsigned XOrder = hasOperandAt(TValBop, X);
+ unsigned YOrder = hasOperandAt(TValBop, Y);
+ unsigned SKB = isSpecialKnownBitsFor(CmpLHSBop, C);
+
+ KnownBits Known;
+ if (TValBop->isBitwiseLogicOp()) {
+ if (SKB != SpecialKnownBits::NothingSpecial && XOrder && YOrder) {
+ if (SKB & SpecialKnownBits::NoCommonBits) {
+ if (SKB & (SpecialKnownBits::AllBitsEnabled)) {
+ if (TValBop->getOpcode() == Instruction::Xor)
+ Known = KnownBits::makeConstant(APInt(BitWidth, -1));
+ }
+ if (TValBop->getOpcode() == Instruction::And)
+ Known = KnownBits::makeConstant(APInt(BitWidth, 0));
+ else if ((match(TVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
+ match(FVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) ||
+ (match(TVal, m_c_Xor(m_Specific(X), m_Specific(Y))) &&
+ match(FVal, m_c_Or(m_Specific(X), m_Specific(Y)))))
+ return IC.replaceInstUsesWith(SI, FVal);
+ } else if (SKB & SpecialKnownBits::AllCommonBits) {
+ if (TValBop->getOpcode() == Instruction::And ||
+ TValBop->getOpcode() == Instruction::Or)
+ if (TValBop->hasOneUse())
+ return IC.replaceOperand(SI, 1, X);
+ } else if (SKB & SpecialKnownBits::AllBitsEnabled) {
+ if (TValBop->getOpcode() == Instruction::Or)
+ Known = KnownBits::makeConstant(APInt(BitWidth, -1));
+ }
+ } else {
+ KnownBits XKnown, YKnown, Temp;
+ KnownBits TValBop0KB, TValBop1KB;
+ XKnown = IC.computeKnownBits(X, 0, &SI);
+ IC.computeKnownBitsFromCond(X, ICI, XKnown, 0, &SI, false);
+ YKnown = IC.computeKnownBits(Y, 0, &SI);
+ IC.computeKnownBitsFromCond(Y, ICI, YKnown, 0, &SI, false);
+
+ // Estimate additional KnownBits from the relationship between X and Y
+ CmpInst::Predicate Pred = ICI->getPredicate();
+ if (Pred == ICmpInst::ICMP_EQ) {
+ if (CmpLHSBop->getOpcode() == Instruction::And) {
+ XKnown.Zero |= ~*C & YKnown.One;
+ YKnown.Zero |= ~*C & XKnown.One;
+ }
+ if (CmpLHSBop->getOpcode() == Instruction::Or) {
+ XKnown.One |= *C & YKnown.Zero;
+ YKnown.One |= *C & XKnown.Zero;
+ }
+ if (CmpLHSBop->getOpcode() == Instruction::Xor) {
+ XKnown.One |= *C & YKnown.Zero;
+ XKnown.Zero |= *C & YKnown.One;
+ YKnown.One |= *C & XKnown.Zero;
+ YKnown.Zero |= *C & XKnown.One;
+ XKnown.Zero |= ~*C & YKnown.Zero;
+ XKnown.One |= ~*C & YKnown.One;
+ YKnown.Zero |= ~*C & XKnown.Zero;
+ YKnown.One |= ~*C & XKnown.One;
+ }
+ }
+
+ auto getTValBopKB = [&](unsigned OpNum) -> KnownBits {
+ unsigned Order = OpNum + 1;
+ if (Order == XOrder)
+ return XKnown;
+ else if (Order == YOrder)
+ return YKnown;
+
+ Value *V = TValBop->getOperand(OpNum);
+ KnownBits Known = IC.computeKnownBits(V, 0, &SI);
+ return Known;
+ };
+ TValBop0KB = getTValBopKB(0);
+ TValBop1KB = getTValBopKB(1);
+ Known = analyzeKnownBitsFromAndXorOr(
+ cast<Operator>(TValBop), TValBop0KB, TValBop1KB, 0,
+ IC.getSimplifyQuery().getWithInstruction(&SI));
+ }
+ }
+
+ if (Known.isConstant()) {
+ auto Const = ConstantInt::get(TValTy, Known.getConstant());
+ return IC.replaceOperand(SI, 1, Const);
+ }
+
+ return nullptr;
+}
+
/// Visit a SelectInst that has an ICmpInst as its first operand.
Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
ICmpInst *ICI) {
@@ -1951,6 +2103,10 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
return replaceInstUsesWith(SI, V);
+ if (Instruction *NewSel = foldSelectICmpBinOp(SI, ICI, CmpLHS, CmpRHS,
+ TrueVal, FalseVal, *this))
+ return NewSel;
+
return Changed ? &SI : nullptr;
}
>From 2a2575ac6c4f858b8900129df033615408b40aa1 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Fri, 10 May 2024 22:41:32 +0900
Subject: [PATCH 4/7] [InstCombine] Optimize TrueVal through knownbits from
cond in selectInst
There are two type of change with this patch.
When the Cond of SelectInst is ICmpInst.
first is a special case where optimizations can be made. For example,
in the case of (icmp eq (xor x, y) -1), it is impossible to estimate
the bits of x and y, but the relationship between the bits of x and y
is known. We define this as NoCommonBits | AllCommonBits.
if (and x, y) is a trueval with this cond, then x and y are in
NoCommonBits state, so (and x, y) is zero.
second is that if the cond allows us to estimate the KnownBits of X
or Y, then if TrueVal is a BinOp consisting of X or Y, we can optimize
it. For example, if (icmp eq (or x, y) 0), then both x and y have
KnownBits that can be estimated to be 0. Therefore, something like
(select (icmp eq (or x, y) 0), (xor x, y), (or x, y)) can be optimized
to (or x, y).
---
.../InstCombine/select-of-bittest.ll | 80 +++++---------
llvm/test/Transforms/InstCombine/select.ll | 100 +++++-------------
2 files changed, 50 insertions(+), 130 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/select-of-bittest.ll b/llvm/test/Transforms/InstCombine/select-of-bittest.ll
index 64cde528599b1..b81b90c1a948e 100644
--- a/llvm/test/Transforms/InstCombine/select-of-bittest.ll
+++ b/llvm/test/Transforms/InstCombine/select-of-bittest.ll
@@ -7,9 +7,8 @@
define i8 @src_and_bit(i8 %x, i8 %y) {
; CHECK-LABEL: @src_and_bit(
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], 3
-; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 2
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], 2
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 [[AND1]], i8 1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 2, i8 1
; CHECK-NEXT: ret i8 [[COND]]
;
%and = and i8 %x, 3
@@ -23,9 +22,8 @@ define i8 @src_and_bit(i8 %x, i8 %y) {
define <2 x i8> @src_and_bit_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_and_bit_vec(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 2, i8 2>
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 2, i8 2>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %x, <i8 3, i8 3>
@@ -39,9 +37,8 @@ define <2 x i8> @src_and_bit_vec(<2 x i8> %x, <2 x i8> %y) {
define <2 x i8> @src_and_bit_vec_poison(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_and_bit_vec_poison(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 2, i8 2>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %x, <i8 poison, i8 3>
@@ -55,9 +52,8 @@ define <2 x i8> @src_and_bit_vec_poison(<2 x i8> %x, <2 x i8> %y) {
define <2 x i8> @src_and_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_and_bit_vec_poison2(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 2, i8 2>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %x, <i8 poison, i8 3>
@@ -71,9 +67,8 @@ define <2 x i8> @src_and_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y) {
define i8 @src_and_bit_ne(i8 %x, i8 %y) {
; CHECK-LABEL: @src_and_bit_ne(
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], 3
-; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 2
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[AND]], 2
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 [[AND1]], i8 1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 2, i8 1
; CHECK-NEXT: ret i8 [[COND]]
;
%and = and i8 %x, 3
@@ -87,9 +82,8 @@ define i8 @src_and_bit_ne(i8 %x, i8 %y) {
define <2 x i8> @src_and_bit_vec_ne(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_and_bit_vec_ne(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 2, i8 2>
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 2, i8 2>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %x, <i8 3, i8 3>
@@ -103,9 +97,8 @@ define <2 x i8> @src_and_bit_vec_ne(<2 x i8> %x, <2 x i8> %y) {
define <2 x i8> @src_and_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_and_bit_vec_poison_ne(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 2, i8 2>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %x, <i8 poison, i8 3>
@@ -119,9 +112,8 @@ define <2 x i8> @src_and_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y) {
define <2 x i8> @src_and_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_and_bit_vec_poison2_ne(
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 poison, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 2>
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[AND]], <i8 2, i8 2>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 2, i8 2>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %x, <i8 poison, i8 3>
@@ -135,13 +127,11 @@ define <2 x i8> @src_and_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y) {
; ====================== OR =======================
define i8 @src_or_bit(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @src_or_bit(
-; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], 3
; CHECK-NEXT: [[AND1:%.*]] = shl i8 [[Y:%.*]], 2
; CHECK-NEXT: [[SHL:%.*]] = and i8 [[AND1]], 12
; CHECK-NEXT: [[OR:%.*]] = or i8 [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 3
-; CHECK-NEXT: [[OR2:%.*]] = or i8 [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 [[OR2]], i8 1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 3, i8 1
; CHECK-NEXT: ret i8 [[COND]]
;
%and = and i8 %z, 3
@@ -156,13 +146,11 @@ define i8 @src_or_bit(i8 %x, i8 %y, i8 %z) {
define <2 x i8> @src_or_bit_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @src_or_bit_vec(
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 3>
; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 2>
; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 12>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
-; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %z, <i8 3, i8 3>
@@ -177,13 +165,11 @@ define <2 x i8> @src_or_bit_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
define <2 x i8> @src_or_bit_vec_poison(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @src_or_bit_vec_poison(
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 poison>
; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 poison>
; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 poison>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
-; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %z, <i8 3, i8 poison>
@@ -198,13 +184,11 @@ define <2 x i8> @src_or_bit_vec_poison(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
define <2 x i8> @src_or_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @src_or_bit_vec_poison2(
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 poison, i8 3>
; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 poison, i8 2>
; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 poison, i8 12>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
-; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %z, <i8 poison, i8 3>
@@ -219,13 +203,11 @@ define <2 x i8> @src_or_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
define i8 @src_or_bit_ne(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @src_or_bit_ne(
-; CHECK-NEXT: [[AND:%.*]] = and i8 [[Z:%.*]], 3
; CHECK-NEXT: [[AND1:%.*]] = shl i8 [[Y:%.*]], 2
; CHECK-NEXT: [[SHL:%.*]] = and i8 [[AND1]], 12
; CHECK-NEXT: [[OR:%.*]] = or i8 [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[OR]], 3
-; CHECK-NEXT: [[OR2:%.*]] = or i8 [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 [[OR2]], i8 1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 3, i8 1
; CHECK-NEXT: ret i8 [[COND]]
;
%and = and i8 %z, 3
@@ -240,13 +222,11 @@ define i8 @src_or_bit_ne(i8 %x, i8 %y, i8 %z) {
define <2 x i8> @src_or_bit_vec_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @src_or_bit_vec_ne(
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 3>
; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 2>
; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 12>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
-; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %z, <i8 3, i8 3>
@@ -261,13 +241,11 @@ define <2 x i8> @src_or_bit_vec_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
define <2 x i8> @src_or_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @src_or_bit_vec_poison_ne(
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 3, i8 poison>
; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 2, i8 poison>
; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 12, i8 poison>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
-; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %z, <i8 3, i8 poison>
@@ -282,13 +260,11 @@ define <2 x i8> @src_or_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z)
define <2 x i8> @src_or_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @src_or_bit_vec_poison2_ne(
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Z:%.*]], <i8 poison, i8 3>
; CHECK-NEXT: [[AND1:%.*]] = shl <2 x i8> [[Y:%.*]], <i8 poison, i8 2>
; CHECK-NEXT: [[SHL:%.*]] = and <2 x i8> [[AND1]], <i8 poison, i8 12>
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[SHL]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR]], <i8 3, i8 3>
-; CHECK-NEXT: [[OR2:%.*]] = or <2 x i8> [[AND]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[OR2]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %z, <i8 poison, i8 3>
@@ -307,8 +283,7 @@ define i8 @src_xor_bit(i8 %x, i8 %y) {
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y:%.*]], 12
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[XOR]], 3
-; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 3
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 [[AND1]], i8 1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i8 3, i8 1
; CHECK-NEXT: ret i8 [[COND]]
;
%and = and i8 %y, 12
@@ -324,8 +299,7 @@ define <2 x i8> @src_xor_bit_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 12, i8 12>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %y, <i8 12, i8 12>
@@ -341,8 +315,7 @@ define <2 x i8> @src_xor_bit_vec_poison(<2 x i8> %x, <2 x i8> %y) {
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 3>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %y, <i8 poison, i8 12>
@@ -358,8 +331,7 @@ define <2 x i8> @src_xor_bit_vec_poison2(<2 x i8> %x, <2 x i8> %y) {
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %y, <i8 poison, i8 12>
@@ -375,8 +347,7 @@ define i8 @src_xor_bit_ne(i8 %x, i8 %y) {
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y:%.*]], 12
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[XOR]], 3
-; CHECK-NEXT: [[AND1:%.*]] = and i8 [[X]], 3
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 [[AND1]], i8 1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i8 3, i8 1
; CHECK-NEXT: ret i8 [[COND]]
;
%and = and i8 %y, 12
@@ -392,8 +363,7 @@ define <2 x i8> @src_xor_bit_vec_ne(<2 x i8> %x, <2 x i8> %y) {
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 12, i8 12>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %y, <i8 12, i8 12>
@@ -409,8 +379,7 @@ define <2 x i8> @src_xor_bit_vec_poison_ne(<2 x i8> %x, <2 x i8> %y) {
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 poison, i8 3>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %y, <i8 poison, i8 12>
@@ -426,8 +395,7 @@ define <2 x i8> @src_xor_bit_vec_poison2_ne(<2 x i8> %x, <2 x i8> %y) {
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[Y:%.*]], <i8 poison, i8 12>
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[AND]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[XOR]], <i8 3, i8 3>
-; CHECK-NEXT: [[AND1:%.*]] = and <2 x i8> [[X]], <i8 3, i8 3>
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[AND1]], <2 x i8> <i8 1, i8 1>
+; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> <i8 3, i8 3>, <2 x i8> <i8 1, i8 1>
; CHECK-NEXT: ret <2 x i8> [[COND]]
;
%and = and <2 x i8> %y, <i8 poison, i8 12>
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index ea37792b5777f..8e8414a906b1b 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3950,16 +3950,11 @@ entry:
; https://alive2.llvm.org/ce/z/QXQDwF
; X&Y==C?X|Y:X^Y, X&Y==C?X^Y:X|Y
-; TODO: X&Y==0 could imply no_common_bit to TrueValue
define i32 @src_and_eq_0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_0_or_xor(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[XOR]]
;
entry:
%and = and i32 %y, %x
@@ -3972,12 +3967,8 @@ entry:
define i32 @src_and_ne_0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_ne_0_xor_or(
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[OR]], i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[XOR]]
;
%and = and i32 %y, %x
%cmp = icmp ne i32 %and, 0
@@ -3987,16 +3978,11 @@ define i32 @src_and_ne_0_xor_or(i32 %x, i32 %y) {
ret i32 %cond
}
-; TODO: X&Y==0 could imply no_common_bit to TrueValue
define i32 @src_and_eq_0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_0_xor_or(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[OR]]
;
entry:
%and = and i32 %y, %x
@@ -4009,12 +3995,8 @@ entry:
define i32 @src_and_ne_0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_ne_0_or_xor(
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%and = and i32 %y, %x
%cmp = icmp ne i32 %and, 0
@@ -4024,15 +4006,13 @@ define i32 @src_and_ne_0_or_xor(i32 %x, i32 %y) {
ret i32 %cond
}
-; TODO: X&Y==-1 could imply all_common_bit to TrueValue
define i32 @src_and_eq_neg1_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_neg1_or_xor(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 -1, i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -4048,9 +4028,8 @@ define i32 @src_and_ne_neg1_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_ne_neg1_xor_or(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 -1, i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%and = and i32 %y, %x
@@ -4061,15 +4040,13 @@ define i32 @src_and_ne_neg1_xor_or(i32 %x, i32 %y) {
ret i32 %cond
}
-; TODO: X&Y==-1 could imply all_common_bit to TrueValue
define i32 @src_and_eq_neg1_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_neg1_xor_or(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], -1
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[OR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 0, i32 [[OR]]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -4085,9 +4062,8 @@ define i32 @src_and_ne_neg1_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_ne_neg1_or_xor(
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], -1
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[OR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 0, i32 [[OR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%and = and i32 %y, %x
@@ -4193,15 +4169,13 @@ entry:
; https://alive2.llvm.org/ce/z/9RPwfN
; X|Y==C?X&Y:X^Y, X|Y==C?X^Y:X&Y
-; TODO: X|Y==0 could imply no_common_bit to TrueValue
define i32 @src_or_eq_0_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_0_and_xor(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 0, i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -4217,9 +4191,8 @@ define i32 @src_or_ne_0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_ne_0_xor_and(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 0, i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%or = or i32 %y, %x
@@ -4230,15 +4203,13 @@ define i32 @src_or_ne_0_xor_and(i32 %x, i32 %y) {
ret i32 %cond
}
-; TODO: X|Y==0 could imply no_common_bit to TrueValue
define i32 @src_or_eq_0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_0_xor_and(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[AND]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 0, i32 [[AND]]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -4254,9 +4225,8 @@ define i32 @src_or_ne_0_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_ne_0_and_xor(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[AND]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 0, i32 [[AND]]
; CHECK-NEXT: ret i32 [[COND]]
;
%or = or i32 %y, %x
@@ -4513,10 +4483,7 @@ define i32 @src_select_or_ne0_xor_or(i32 %x, i32 %y) {
define i32 @src_select_or_eq0_and_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_or_eq0_and_or(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[AND]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, %y
%or0 = icmp eq i32 %or, 0
@@ -4528,10 +4495,7 @@ define i32 @src_select_or_eq0_and_or(i32 %x, i32 %y) {
define i32 @src_select_or_ne0_or_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_or_ne0_or_and(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 [[AND]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, %y
%or0 = icmp ne i32 %or, 0
@@ -4544,8 +4508,7 @@ define i32 @src_select_xor_eq0_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_eq0_and_xor(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4559,8 +4522,7 @@ define i32 @src_select_xor_ne0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_ne0_xor_and(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[AND]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[X]], i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4574,8 +4536,7 @@ define i32 @src_select_xor_eq0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_eq0_or_xor(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4589,8 +4550,7 @@ define i32 @src_select_xor_ne0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_ne0_xor_or(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[OR]], i32 [[XOR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[X]], i32 [[XOR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4603,10 +4563,7 @@ define i32 @src_select_xor_ne0_xor_or(i32 %x, i32 %y) {
define i32 @src_select_or_eq0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_or_eq0_xor_or(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, %y
%or0 = icmp eq i32 %or, 0
@@ -4618,10 +4575,7 @@ define i32 @src_select_or_eq0_xor_or(i32 %x, i32 %y) {
define i32 @src_select_or_ne0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_or_ne0_or_xor(
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, %y
%or0 = icmp ne i32 %or, 0
@@ -4634,9 +4588,8 @@ define i32 @src_select_xor_max_negative_int(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_max_negative_int(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], -1
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[OR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4651,9 +4604,8 @@ define i32 @src_select_xor_max_negative_int_ne(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_max_negative_int_ne(
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], -1
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[AND]], i32 [[OR]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 0, i32 [[OR]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
>From e2eb1ff7a83fec782a4bfe91944143b2850984f1 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Fri, 14 Jun 2024 01:56:07 +0900
Subject: [PATCH 5/7] add disjoint to special knownbits
---
.../InstCombine/InstCombineSelect.cpp | 5 ++
llvm/test/Transforms/InstCombine/select.ll | 60 ++++---------------
2 files changed, 18 insertions(+), 47 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 038e10c4c5202..bd9f9f5297d36 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1858,6 +1858,11 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
return NoCommonBits | AllBitsEnabled;
if (CmpRHS->isZero())
return AllCommonBits;
+ } else if (auto Disjoint = dyn_cast<PossiblyDisjointInst>(CmpLHS);
+ Disjoint->isDisjoint()) {
+ if (CmpRHS->isAllOnes())
+ return NoCommonBits | AllBitsEnabled;
+ return NoCommonBits;
}
return NothingSpecial;
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 8e8414a906b1b..cd4ae03387335 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3763,11 +3763,7 @@ exit:
define i32 @src_or_disjoint_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_disjoint_xor(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 -1
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 -1
;
entry:
%or.disjoint = or disjoint i32 %x, %y
@@ -3780,11 +3776,7 @@ entry:
define i32 @src_or_disjoint_xor_comm(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_disjoint_xor_comm(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 -1
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 -1
;
entry:
%or.disjoint = or disjoint i32 %x, %y
@@ -3797,11 +3789,7 @@ entry:
define i32 @src_or_disjoint_xor_ne(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_disjoint_xor_ne(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 -1
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 -1
;
entry:
%or.disjoint = or disjoint i32 %x, %y
@@ -3814,11 +3802,7 @@ entry:
define i32 @src_or_disjoint_xor_ne_comm(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_disjoint_xor_ne_comm(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[OR_DISJOINT]], -1
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 -1
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 -1
;
entry:
%or.disjoint = or disjoint i32 %y, %x
@@ -3831,11 +3815,7 @@ entry:
define <2 x i8> @src_or_disjoint_xor_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_or_disjoint_xor_vec(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
-; CHECK-NEXT: ret <2 x i8> [[COND]]
+; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1>
;
entry:
%or.disjoint = or disjoint <2 x i8> %x, %y
@@ -3848,11 +3828,7 @@ entry:
define <2 x i8> @src_or_disjoint_xor_comm_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_or_disjoint_xor_comm_vec(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
-; CHECK-NEXT: ret <2 x i8> [[COND]]
+; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1>
;
entry:
%or.disjoint = or disjoint <2 x i8> %x, %y
@@ -3865,11 +3841,7 @@ entry:
define <2 x i8> @src_or_disjoint_xor_ne_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_or_disjoint_xor_ne_vec(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
-; CHECK-NEXT: ret <2 x i8> [[COND]]
+; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1>
;
entry:
%or.disjoint = or disjoint <2 x i8> %x, %y
@@ -3882,11 +3854,7 @@ entry:
define <2 x i8> @src_or_disjoint_xor_ne_comm_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @src_or_disjoint_xor_ne_comm_vec(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR_DISJOINT:%.*]] = or disjoint <2 x i8> [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq <2 x i8> [[OR_DISJOINT]], <i8 -1, i8 -1>
-; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i8> [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select <2 x i1> [[CMP_NOT]], <2 x i8> [[XOR]], <2 x i8> <i8 -1, i8 -1>
-; CHECK-NEXT: ret <2 x i8> [[COND]]
+; CHECK-NEXT: ret <2 x i8> <i8 -1, i8 -1>
;
entry:
%or.disjoint = or disjoint <2 x i8> %y, %x
@@ -4924,13 +4892,11 @@ define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
ret i32 %cond
}
-; https://alive2.llvm.org/ce/z/SBe8ei
-define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_no_trans_select_xor_eq0_or_xor(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]]
+define i32 @src_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_trans_select_xor_eq0_or_xor(
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
>From 6237579b08beab96a57b39c05a1a439e0a8c4db8 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Fri, 14 Jun 2024 05:08:56 +0900
Subject: [PATCH 6/7] add comments
---
.../InstCombine/InstCombineSelect.cpp | 28 +++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index bd9f9f5297d36..1903c7f99fe3d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1886,52 +1886,74 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
KnownBits Known;
if (TValBop->isBitwiseLogicOp()) {
+ // We handle if we know specific knownbits from cond of selectinst.
+ // ex) X&Y==-1 ? X^Y : False
if (SKB != SpecialKnownBits::NothingSpecial && XOrder && YOrder) {
+ // No common bits between X, Y
if (SKB & SpecialKnownBits::NoCommonBits) {
if (SKB & (SpecialKnownBits::AllBitsEnabled)) {
+ // If X op Y == -1, then XOR must be -1
if (TValBop->getOpcode() == Instruction::Xor)
Known = KnownBits::makeConstant(APInt(BitWidth, -1));
}
+ // If Trueval is X&Y then it should be 0.
if (TValBop->getOpcode() == Instruction::And)
Known = KnownBits::makeConstant(APInt(BitWidth, 0));
+ // X|Y can be replace with X^Y, X^Y can be replace with X|Y
+ // This replacing is meaningful when falseval is same.
else if ((match(TVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
match(FVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) ||
(match(TVal, m_c_Xor(m_Specific(X), m_Specific(Y))) &&
match(FVal, m_c_Or(m_Specific(X), m_Specific(Y)))))
return IC.replaceInstUsesWith(SI, FVal);
+ // All common bits between X, Y
} else if (SKB & SpecialKnownBits::AllCommonBits) {
+ // We can replace (X&Y) and (X|Y) to X or Y
if (TValBop->getOpcode() == Instruction::And ||
TValBop->getOpcode() == Instruction::Or)
if (TValBop->hasOneUse())
return IC.replaceOperand(SI, 1, X);
} else if (SKB & SpecialKnownBits::AllBitsEnabled) {
+ // We can replace (X|Y) to -1
if (TValBop->getOpcode() == Instruction::Or)
Known = KnownBits::makeConstant(APInt(BitWidth, -1));
}
} else {
KnownBits XKnown, YKnown, Temp;
KnownBits TValBop0KB, TValBop1KB;
+ // computeKnowBits calculates the KnownBits in the branching condition
+ // that the specified variable passes in the execution flow. however, it
+ // does not contain the SelectInst condition, so there is an optimization
+ // opportunity to update the knownbits obtained by calculating KnownBits
+ // with the SelectInst condition.
XKnown = IC.computeKnownBits(X, 0, &SI);
IC.computeKnownBitsFromCond(X, ICI, XKnown, 0, &SI, false);
YKnown = IC.computeKnownBits(Y, 0, &SI);
IC.computeKnownBitsFromCond(Y, ICI, YKnown, 0, &SI, false);
-
- // Estimate additional KnownBits from the relationship between X and Y
CmpInst::Predicate Pred = ICI->getPredicate();
if (Pred == ICmpInst::ICMP_EQ) {
+ // Estimate additional KnownBits from the relationship between X and Y
if (CmpLHSBop->getOpcode() == Instruction::And) {
+ // The bit that are set to 1 at `~C&Y` must be 0 in X
+ // The bit that are set to 1 at `~C&X` must be 0 in Y
XKnown.Zero |= ~*C & YKnown.One;
YKnown.Zero |= ~*C & XKnown.One;
}
if (CmpLHSBop->getOpcode() == Instruction::Or) {
+ // The bit that are set to 0 at `C&Y` must be 1 in X
+ // The bit that are set to 0 at `C&X` must be 1 in Y
XKnown.One |= *C & YKnown.Zero;
YKnown.One |= *C & XKnown.Zero;
}
if (CmpLHSBop->getOpcode() == Instruction::Xor) {
+ // If X^Y==C, then X and Y must be either (1,0) or (0,1) for the
+ // enabled bits in C.
XKnown.One |= *C & YKnown.Zero;
XKnown.Zero |= *C & YKnown.One;
YKnown.One |= *C & XKnown.Zero;
YKnown.Zero |= *C & XKnown.One;
+ // If X^Y==C, then X and Y must be either (0,0) or (1,1) for the
+ // disabled bits in C.
XKnown.Zero |= ~*C & YKnown.Zero;
XKnown.One |= ~*C & YKnown.One;
YKnown.Zero |= ~*C & XKnown.Zero;
@@ -1939,6 +1961,8 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
}
}
+ // If TrueVal has X or Y, return the corresponding KnownBits, otherwise
+ // compute and return new KnownBits.
auto getTValBopKB = [&](unsigned OpNum) -> KnownBits {
unsigned Order = OpNum + 1;
if (Order == XOrder)
>From 21fa11d3fd3b324ee07fe876a84a0cebe72ccb77 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Fri, 14 Jun 2024 07:09:36 +0900
Subject: [PATCH 7/7] support X==Y that transformed from X^Y==0
---
.../InstCombine/InstCombineSelect.cpp | 53 +++++++++++--------
llvm/test/Transforms/InstCombine/select.ll | 39 +++++++-------
2 files changed, 51 insertions(+), 41 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 1903c7f99fe3d..3d667ec5f1b3f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1831,11 +1831,26 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
InstCombinerImpl &IC) {
Value *X, *Y;
const APInt *C;
-
- if (!((match(CmpLHS, m_BinOp(m_Value(X), m_Value(Y))) &&
- match(CmpRHS, m_APInt(C))) &&
- (match(TVal, m_c_BinOp(m_Specific(X), m_Value())) ||
- match(TVal, m_c_BinOp(m_Specific(Y), m_Value())))))
+ unsigned CmpLHSOpc;
+ bool IsDisjoint = false;
+ // Specially handling for X^Y==0 transformed to X==Y
+ if (match(TVal, m_c_BitwiseLogic(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
+ X = CmpLHS;
+ Y = CmpRHS;
+ APInt ZeroVal = APInt::getZero(CmpLHS->getType()->getScalarSizeInBits());
+ C = const_cast<APInt *>(&ZeroVal);
+ CmpLHSOpc = Instruction::Xor;
+ } else if ((match(CmpLHS, m_BinOp(m_Value(X), m_Value(Y))) &&
+ match(CmpRHS, m_APInt(C))) &&
+ (match(TVal, m_c_BinOp(m_Specific(X), m_Value())) ||
+ match(TVal, m_c_BinOp(m_Specific(Y), m_Value())))) {
+ if (auto Inst = dyn_cast<PossiblyDisjointInst>(CmpLHS)) {
+ if (Inst->isDisjoint())
+ IsDisjoint = true;
+ CmpLHSOpc = Instruction::Or;
+ } else
+ CmpLHSOpc = cast<BinaryOperator>(CmpLHS)->getOpcode();
+ } else
return nullptr;
enum SpecialKnownBits {
@@ -1847,20 +1862,17 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
// We cannot know exactly what bits is known in X Y.
// Instead, we just know what relationship exist for.
- auto isSpecialKnownBitsFor = [&](const Instruction *CmpLHS,
- const APInt *CmpRHS) -> unsigned {
- unsigned Opc = CmpLHS->getOpcode();
- if (Opc == Instruction::And) {
- if (CmpRHS->isZero())
+ auto isSpecialKnownBitsFor = [&]() -> unsigned {
+ if (CmpLHSOpc == Instruction::And) {
+ if (C->isZero())
return NoCommonBits;
- } else if (Opc == Instruction::Xor) {
- if (CmpRHS->isAllOnes())
+ } else if (CmpLHSOpc == Instruction::Xor) {
+ if (C->isAllOnes())
return NoCommonBits | AllBitsEnabled;
- if (CmpRHS->isZero())
+ if (C->isZero())
return AllCommonBits;
- } else if (auto Disjoint = dyn_cast<PossiblyDisjointInst>(CmpLHS);
- Disjoint->isDisjoint()) {
- if (CmpRHS->isAllOnes())
+ } else if (CmpLHSOpc == Instruction::Or && IsDisjoint) {
+ if (C->isAllOnes())
return NoCommonBits | AllBitsEnabled;
return NoCommonBits;
}
@@ -1879,10 +1891,9 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
Type *TValTy = TVal->getType();
unsigned BitWidth = TVal->getType()->getScalarSizeInBits();
auto TValBop = cast<BinaryOperator>(TVal);
- auto CmpLHSBop = cast<BinaryOperator>(CmpLHS);
unsigned XOrder = hasOperandAt(TValBop, X);
unsigned YOrder = hasOperandAt(TValBop, Y);
- unsigned SKB = isSpecialKnownBitsFor(CmpLHSBop, C);
+ unsigned SKB = isSpecialKnownBitsFor();
KnownBits Known;
if (TValBop->isBitwiseLogicOp()) {
@@ -1933,19 +1944,19 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
CmpInst::Predicate Pred = ICI->getPredicate();
if (Pred == ICmpInst::ICMP_EQ) {
// Estimate additional KnownBits from the relationship between X and Y
- if (CmpLHSBop->getOpcode() == Instruction::And) {
+ if (CmpLHSOpc == Instruction::And) {
// The bit that are set to 1 at `~C&Y` must be 0 in X
// The bit that are set to 1 at `~C&X` must be 0 in Y
XKnown.Zero |= ~*C & YKnown.One;
YKnown.Zero |= ~*C & XKnown.One;
}
- if (CmpLHSBop->getOpcode() == Instruction::Or) {
+ if (CmpLHSOpc == Instruction::Or) {
// The bit that are set to 0 at `C&Y` must be 1 in X
// The bit that are set to 0 at `C&X` must be 1 in Y
XKnown.One |= *C & YKnown.Zero;
YKnown.One |= *C & XKnown.Zero;
}
- if (CmpLHSBop->getOpcode() == Instruction::Xor) {
+ if (CmpLHSOpc == Instruction::Xor) {
// If X^Y==C, then X and Y must be either (1,0) or (0,1) for the
// enabled bits in C.
XKnown.One |= *C & YKnown.Zero;
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index cd4ae03387335..6f95c379e9f29 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -4474,9 +4474,9 @@ define i32 @src_select_or_ne0_or_and(i32 %x, i32 %y) {
define i32 @src_select_xor_eq0_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_eq0_and_xor(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 [[XOR]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4488,9 +4488,9 @@ define i32 @src_select_xor_eq0_and_xor(i32 %x, i32 %y) {
define i32 @src_select_xor_ne0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_ne0_xor_and(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[X]], i32 [[XOR]]
+; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0_NOT]], i32 0, i32 [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4502,9 +4502,9 @@ define i32 @src_select_xor_ne0_xor_and(i32 %x, i32 %y) {
define i32 @src_select_xor_eq0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_eq0_or_xor(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 [[XOR]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4516,9 +4516,9 @@ define i32 @src_select_xor_eq0_or_xor(i32 %x, i32 %y) {
define i32 @src_select_xor_ne0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_select_xor_ne0_xor_or(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[X]], i32 [[XOR]]
+; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0_NOT]], i32 0, i32 [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
@@ -4863,8 +4863,8 @@ define i32 @src_no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
ret i32 %cond
}
-define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_no_trans_select_xor_eq0_xor_or(
+define i32 @src_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_trans_select_xor_eq0_xor_or(
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[OR]]
@@ -4877,12 +4877,11 @@ define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
ret i32 %cond
}
-define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
-; CHECK-LABEL: @src_no_trans_select_xor_eq0_and_xor(
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
+define i32 @src_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_trans_select_xor_eq0_and_xor(
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
+; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
; CHECK-NEXT: ret i32 [[COND]]
;
%xor = xor i32 %x, %y
More information about the llvm-commits
mailing list