[llvm] [InstCombine] Try optimizing with knownbits which determined from Cond (PR #91762)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 14 02:10:36 PDT 2024
https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/91762
>From 09bc4efe9b6881463e6a897b43af349695d6c736 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 deeef25eefab374e3fe485efd7067eabc74b7c36 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 f877f01b030c0f055395f85be291b5776b5cf80f 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 fcda8097b8441eeaad65307beaad122512d70a11 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 c510b2c7bf5f713bebea97f3a8506808957b4724 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 c61f74e4f1339441b2b4f8ad9b7e5e85f17e30ba 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 0d64c0c0f629d206bba59498f923d58239d2c264 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