[llvm] [InstSimplify] Simplify select if it combinated `and/or/xor` (PR #73362)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 28 04:23:00 PST 2023
https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/73362
>From 7eb3070bb3c44cef0be163c47ea92811669c6254 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Mon, 27 Nov 2023 09:11:03 +0900
Subject: [PATCH 1/2] [InstSimplify] Add test for simplify select if it
combinated and/or/xor
- (X & Y) == 0 ? X | Y : X ^ Y --> X ^ Y
- (X & Y) != 0 ? X | Y : X ^ Y --> X | Y
- (X | Y) == 0 ? X & Y : X ^ Y --> X ^ Y
- (X | Y) != 0 ? X & Y : X ^ Y --> X & Y
- (X ^ Y) == 0 ? X | Y : X & Y --> X & Y
- (X ^ Y) != 0 ? X | Y : X & Y --> X | Y
certain combinations of bitwise operators can be simplified to
returning the value of the True or False clause.
Proofs : https://alive2.llvm.org/ce/z/_VW7Fo
---
llvm/test/Transforms/InstSimplify/select.ll | 661 ++++++++++++++++++++
1 file changed, 661 insertions(+)
diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll
index c85c4d03000feaf..cb46f475403b6f7 100644
--- a/llvm/test/Transforms/InstSimplify/select.ll
+++ b/llvm/test/Transforms/InstSimplify/select.ll
@@ -1652,3 +1652,664 @@ define i8 @select_xor_cmp_unmatched_operands(i8 %0, i8 %1, i8 %c) {
%5 = select i1 %3, i8 0, i8 %4
ret i8 %5
}
+
+; Select icmp and/or/xor
+; X&Y==0 ? X|Y : X^Y -> X|Y
+define i32 @src_select_and_eq0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_eq0_or_xor(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[XOR:%.*]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 0
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+; X&Y==0 ? X^Y : X|Y -> X|Y
+define i32 @src_select_and_eq0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_eq0_xor_or(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[OR:%.*]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 0
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %xor, i32 %or
+ ret i32 %cond
+}
+; X&Y!=0 ? X|Y : X^Y -> X|Y
+define i32 @src_select_and_ne0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_ne0_or_xor(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[OR:%.*]]
+ %and = and i32 %x, %y
+ %and1 = icmp ne i32 %and, 0
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and1, i32 %or, i32 %xor
+ ret i32 %cond
+}
+; X&Y!=0 ? X^Y : X|Y -> X^Y
+define i32 @src_select_and_ne0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_ne0_xor_or(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[XOR:%.*]]
+ %and = and i32 %x, %y
+ %and1 = icmp ne i32 %and, 0
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and1, i32 %xor, i32 %or
+ ret i32 %cond
+}
+; X|Y==0 ? X&Y : X^Y -> X^Y
+define i32 @src_select_or_eq0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_eq0_and_xor(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[XOR:%.*]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 0
+ %xor = xor i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+; X|Y!=0 ? X&Y : X^Y -> X&Y
+define i32 @src_select_or_ne0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_ne0_and_xor(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[AND:%.*]]
+ %or = or i32 %x, %y
+ %or1 = icmp ne i32 %or, 0
+ %xor = xor i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %or1, i32 %and, i32 %xor
+ ret i32 %cond
+}
+; X|Y==0 ? X^Y : X&Y -> X&Y
+define i32 @src_select_or_eq0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_eq0_xor_and(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[AND:%.*]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 0
+ %xor = xor i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %or0, i32 %xor, i32 %and
+ ret i32 %cond
+}
+; X|Y==0 ? X^Y : X&Y -> X&Y
+define i32 @src_select_or_ne0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_ne0_xor_and(
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[XOR:%.*]]
+ %or = or i32 %x, %y
+ %or1 = icmp ne i32 %or, 0
+ %xor = xor i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %or1, i32 %xor, i32 %and
+ ret i32 %cond
+}
+; X^Y==0 ? X&Y : X|Y -> X|Y
+define i32 @src_select_xor_eq0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_eq0_and_or(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[OR:%.*]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 0
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor0, i32 %and, i32 %or
+ ret i32 %cond
+}
+; X^Y==0 ? X|Y : X&Y -> X|Y
+define i32 @src_select_xor_eq0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_eq0_or_and(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[AND:%.*]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 0
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor0, i32 %or, i32 %and
+ ret i32 %cond
+}
+; X^Y!=0 ? X&Y : X|Y -> X&Y
+define i32 @src_select_xor_ne0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_ne0_and_or(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[AND:%.*]]
+ %xor = xor i32 %x, %y
+ %xor1 = icmp ne i32 %xor, 0
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor1, i32 %and, i32 %or
+ ret i32 %cond
+}
+; X^Y!=0 ? X|Y : X&Y -> X|Y
+define i32 @src_select_xor_ne0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_ne0_or_and(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[OR:%.*]]
+ %xor = xor i32 %x, %y
+ %xor1 = icmp ne i32 %xor, 0
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor1, i32 %or, i32 %and
+ ret i32 %cond
+}
+
+; Extend Xor
+; (X ^ Y) == 0 could be transformed to X == Y
+; (X ^ Y) != 0 could be transformed to X != Y
+
+; X==Y ? X|Y : X&Y -> X&Y
+define i32 @src_select_x_eq_y_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_x_eq_y_or_and(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[AND:%.*]]
+ %xor1 = icmp eq i32 %x, %y
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor1, i32 %or, i32 %and
+ ret i32 %cond
+}
+; X!=Y ? X|Y : X&Y -> X|Y
+define i32 @src_select_x_ne_y_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_x_ne_y_or_and(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[OR:%.*]]
+ %xor1 = icmp ne i32 %x, %y
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor1, i32 %or, i32 %and
+ ret i32 %cond
+}
+; X==Y ? X|Y : X&Y -> X&Y
+define i32 @src_select_x_eq_y_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_x_eq_y_and_or(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[OR:%.*]]
+ %xor1 = icmp eq i32 %x, %y
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor1, i32 %and, i32 %or
+ ret i32 %cond
+}
+; X!=Y ? X|Y : X&Y -> X|Y
+define i32 @src_select_x_ne_y_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_x_ne_y_and_or(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[AND:%.*]]
+ %xor1 = icmp ne i32 %x, %y
+ %or = or i32 %x, %y
+ %and = and i32 %x, %y
+ %cond = select i1 %xor1, i32 %and, i32 %or
+ 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) {
+; CHECK-LABEL: @src_select_and_min_positive_int(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 1
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 1
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_and_max_positive_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_max_positive_int(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 2147483647
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 2147483647
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_and_min_negative_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_min_negative_int(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], -2147483648
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, -2147483648
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_and_max_negative_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and_max_negative_int(
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], -1
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[OR]], i32 [[XOR]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, -1
+ %xor = xor i32 %x, %y
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_or_min_positive_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_min_positive_int(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR:%.*]], 1
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 1
+ %and = and i32 %x, %y
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_or_max_positive_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_max_positive_int(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR:%.*]], 2147483647
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 2147483647
+ %and = and i32 %x, %y
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_or_min_negative_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_min_negative_int(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR:%.*]], -2147483648
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, -2147483648
+ %and = and i32 %x, %y
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_or_max_negative_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or_max_negative_int(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0]] = icmp eq i32 [[OR:%.*]], -1
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[AND]], i32 [[XOR]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, -1
+ %and = and i32 %x, %y
+ %xor = xor i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @src_select_xor_min_positive_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_min_positive_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]]
+ %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_positive_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_max_positive_int(
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 2147483647
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 2147483647
+ %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_min_negative_int(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor_min_negative_int(
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], -2147483648
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[XOR0]], i32 [[AND]], i32 [[OR]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, -2147483648
+ %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(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]]
+ %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
+; NO TRANSFORMED - not supported
+define i32 @no_trans_select_and_eq0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_eq0_and_or(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[AND]], i32 [[OR]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %and, i32 %or
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_eq0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_eq0_and_xor(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[AND]], i32 [[XOR]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %and0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_ne0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_ne0_and_or(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[AND]], i32 [[OR]]
+ %and = and i32 %x, %y
+ %and0 = icmp ne i32 %and, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %and, i32 %or
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_ne0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_ne0_and_xor(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[AND]], i32 [[XOR]]
+ %and = and i32 %x, %y
+ %and0 = icmp ne i32 %and, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %and0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_eq0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_eq0_or_and(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[OR]], i32 [[AND]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %and
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_eq0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_eq0_xor_and(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[XOR]], i32 [[AND]]
+ %and = and i32 %x, %y
+ %and0 = icmp eq i32 %and, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %and0, i32 %xor, i32 %and
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_ne0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_ne0_or_and(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[OR]], i32 [[AND]]
+ %and = and i32 %x, %y
+ %and0 = icmp ne i32 %and, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %and0, i32 %or, i32 %and
+ ret i32 %cond
+}
+define i32 @no_trans_select_and_ne0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_ne0_xor_and(
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[AND0:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[AND0]], i32 [[XOR]], i32 [[AND]]
+ %and = and i32 %x, %y
+ %and0 = icmp ne i32 %and, 0
+ %xor = xor i32 %x, %y
+ %cond = select i1 %and0, i32 %xor, i32 %and
+ ret i32 %cond
+}
+; TODO : This might can be transform to `and i32 %x, %y`
+define i32 @no_trans_select_or_eq0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_or_eq0_or_and(
+; 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 [[OR]], i32 [[AND]]
+ %or = or i32 %x, %y
+ %or0 = icmp eq i32 %or, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %or0, i32 %or, i32 %and
+ ret i32 %cond
+}
+; TODO : This might can be transform to `xor i32 %x, %y`
+define i32 @no_trans_select_or_eq0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @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 [[OR]], i32 [[XOR]]
+ %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 @no_trans_select_or_ne0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_or_ne0_or_and(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp ne i32 [[OR]], 0
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[OR]], i32 [[AND]]
+ %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 @no_trans_select_or_ne0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_or_ne0_or_xor(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp ne i32 [[OR]], 0
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[OR]], i32 [[XOR]]
+ %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
+}
+; TODO : This might can be transform to `or i32 %x, %y`
+define i32 @no_trans_select_or_eq0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @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]]
+ %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 @no_trans_select_or_ne0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_or_ne0_and_or(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp ne i32 [[OR]], 0
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[AND]], i32 [[OR]]
+ %or = or i32 %x, %y
+ %or0 = icmp ne i32 %or, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %or0, i32 %and, i32 %or
+ ret i32 %cond
+}
+define i32 @no_trans_select_or_eq0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @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]]
+ %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
+}
+; TODO : This might can be transform to `xor i32 %x, %y`
+define i32 @no_trans_select_and_ne0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_and_ne0_xor_or(
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR0:%.*]] = icmp ne i32 [[OR]], 0
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[OR0]], i32 [[XOR]], i32 [[OR]]
+ %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 @no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_xor_eq0_xor_and(
+; 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 [[XOR]], i32 [[AND]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %xor0, i32 %xor, i32 %and
+ ret i32 %cond
+}
+define i32 @no_trans_select_xor_ne0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_xor_ne0_xor_and(
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp ne i32 [[XOR]], 0
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[XOR0]], i32 [[XOR]], i32 [[AND]]
+ %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 @no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_xor_eq0_xor_or(
+; 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 [[XOR]], i32 [[OR]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp eq i32 %xor, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %xor0, i32 %xor, i32 %or
+ ret i32 %cond
+}
+define i32 @no_trans_select_xor_ne0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_xor_ne0_xor_or(
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp ne i32 [[XOR]], 0
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[XOR0]], i32 [[XOR]], i32 [[OR]]
+ %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 @no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_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]]
+ %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 @no_trans_select_xor_ne0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_xor_ne0_and_xor(
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp ne i32 [[XOR]], 0
+; CHECK-NEXT: [[AND]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp ne i32 %xor, 0
+ %and = and i32 %x, %y
+ %cond = select i1 %xor0, i32 %and, i32 %xor
+ ret i32 %cond
+}
+define i32 @no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_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]]
+ %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 @no_trans_select_xor_ne0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @no_trans_select_xor_ne0_or_xor(
+; CHECK-NEXT: [[XOR]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT: [[XOR0:%.*]] = icmp ne i32 [[XOR]], 0
+; CHECK-NEXT: [[OR]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[COND]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]]
+ %xor = xor i32 %x, %y
+ %xor0 = icmp ne i32 %xor, 0
+ %or = or i32 %x, %y
+ %cond = select i1 %xor0, i32 %or, i32 %xor
+ ret i32 %cond
+}
>From 65392597d14016b0041bbd5ee556b0ecc945c0f2 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 24 Nov 2023 06:37:57 +0900
Subject: [PATCH 2/2] [InstSimplify] Simplify select if it combinated
`and/or/xor`
- (X & Y) == 0 ? X | Y : X ^ Y --> X ^ Y
- (X & Y) != 0 ? X | Y : X ^ Y --> X | Y
- (X | Y) == 0 ? X & Y : X ^ Y --> X ^ Y
- (X | Y) != 0 ? X & Y : X ^ Y --> X & Y
- (X ^ Y) == 0 ? X | Y : X & Y --> X & Y
- (X ^ Y) != 0 ? X | Y : X & Y --> X | Y
certain combinations of bitwise operators can be simplified to
returning the value of the True or False clause.
Proofs : https://alive2.llvm.org/ce/z/HDSzm4
Fixed llvm#71792.
---
llvm/lib/Analysis/InstructionSimplify.cpp | 58 +++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7ef2ffd23b95e76..1860e45144d21d1 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4425,6 +4425,61 @@ Value *llvm::simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
RecursionLimit);
}
+/// Try simplifying the selection command when condition, trueValue, and
+/// falseValue are combinations of special bitwise operators.
+static Value *simplifySelectBitTestSpec(Value *CmpLHS, Value *CmpRHS,
+ Value *TrueVal, Value *FalseVal) {
+ Value *X, *Y;
+ // (X & Y) == 0 ? X | Y : X ^ Y --> X ^ Y
+ // (X & Y) == 0 ? X ^ Y : X | Y --> X | Y
+ // (X & Y) != 0 ? X | Y : X ^ Y --> X | Y
+ // (X & Y) != 0 ? X ^ Y : X | Y --> X ^ Y
+ if (match(CmpLHS, m_c_And(m_Value(X), m_Value(Y))) &&
+ match(CmpRHS, m_Zero())) {
+ if (match(TrueVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
+ match(FalseVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+ return FalseVal;
+ } else if (match(FalseVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
+ match(TrueVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+ return FalseVal;
+ }
+ }
+ // (X | Y) == 0 ? X & Y : X ^ Y --> X ^ Y
+ // (X | Y) == 0 ? X ^ Y : X & Y --> X & Y
+ // (X | Y) != 0 ? X & Y : X ^ Y --> X & Y
+ // (X | Y) != 0 ? X ^ Y : X & Y --> X ^ Y
+ if (match(CmpLHS, m_c_Or(m_Value(X), m_Value(Y))) &&
+ match(CmpRHS, m_Zero())) {
+ if (match(TrueVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+ match(FalseVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+ return FalseVal;
+ } else if (match(FalseVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+ match(TrueVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+ return FalseVal;
+ }
+ }
+ // (X ^ Y) == 0 ? X | Y : X & Y --> X & Y
+ // (X ^ Y) == 0 ? X & Y : X | Y --> X | Y
+ // (X ^ Y) != 0 ? X | Y : X & Y --> X | Y
+ // (X ^ Y) != 0 ? X & Y : X | Y --> X & Y
+ // (X ^ Y) == 0 could be transformed to X == Y
+ // (X ^ Y) != 0 could be transformed to X != Y
+ if ((!match(CmpRHS, m_Zero()) && match(CmpLHS, m_Value(X)) &&
+ match(CmpRHS, m_Value(Y))) ||
+ (match(CmpRHS, m_Zero()) &&
+ match(CmpLHS, m_Xor(m_Value(X), m_Value(Y))))) {
+ if (match(TrueVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+ match(FalseVal, m_c_Or(m_Specific(X), m_Specific(Y)))) {
+ return FalseVal;
+ } else if (match(FalseVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+ match(TrueVal, m_c_Or(m_Specific(X), m_Specific(Y)))) {
+ return FalseVal;
+ }
+ }
+
+ return nullptr;
+}
+
/// Try to simplify a select instruction when its condition operand is an
/// integer comparison where one operand of the compare is a constant.
static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X,
@@ -4601,6 +4656,9 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
}
}
+ if (Value *V = simplifySelectBitTestSpec(CmpLHS, CmpRHS, TrueVal, FalseVal))
+ return V;
+
if (Pred == ICmpInst::ICMP_EQ && match(CmpRHS, m_Zero())) {
Value *X;
const APInt *Y;
More information about the llvm-commits
mailing list