[llvm] [InstCombine] simplify `icmp pred x, ~x` (PR #73990)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 12 01:27:41 PST 2023
https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/73990
>From c4f3a8fac7dd7e785e490d179b6bce822a1225a8 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 1 Dec 2023 06:28:23 +0900
Subject: [PATCH 1/2] [InstCombine] Add test for simplify `x (comp) ~x`
simplify compare between specific variable `X` and `NOT(X)`
Proof: https://alive2.llvm.org/ce/z/AXlRm5
---
.../Transforms/InstCombine/icmp-of-xor-x.ll | 515 ++++++++++++++++++
1 file changed, 515 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index fd61c8a301662e..b7380d19230de1 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -5,6 +5,521 @@ declare void @llvm.assume(i1)
declare void @barrier()
declare void @use.i8(i8)
+; X op ~X tests. op signed
+; X s< ~X --> X s< 0
+define i1 @src_slt(i8 %x) {
+; CHECK-LABEL: @src_slt(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp slt i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_slt_i128(i128 %x) {
+; CHECK-LABEL: @src_slt_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp slt i128 %x, %not
+ ret i1 %cmp
+}
+; X s> ~X --> X s> -1
+define i1 @src_sgt(i8 %x) {
+; CHECK-LABEL: @src_sgt(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sgt i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_sgt_i128(i128 %x) {
+; CHECK-LABEL: @src_sgt_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp sgt i128 %x, %not
+ ret i1 %cmp
+}
+; X s<= ~X --> X s< 0
+define i1 @src_sle(i8 %x) {
+; CHECK-LABEL: @src_sle(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sle i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_sle_i128(i128 %x) {
+; CHECK-LABEL: @src_sle_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp sle i128 %x, %not
+ ret i1 %cmp
+}
+; X s>= ~X --> X s> -1
+define i1 @src_sge(i8 %x) {
+; CHECK-LABEL: @src_sge(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sge i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_sge_i128(i128 %x) {
+; CHECK-LABEL: @src_sge_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp sge i128 %x, %not
+ ret i1 %cmp
+}
+; X op ~X tests. op signed. commutative
+; ~X s< X --> X s> -1
+define i1 @src_slt_comm(i8 %x) {
+; CHECK-LABEL: @src_slt_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp slt i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_slt_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_slt_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp slt i128 %not, %x
+ ret i1 %cmp
+}
+; ~X s> X --> X s< 0
+define i1 @src_sgt_comm(i8 %x) {
+; CHECK-LABEL: @src_sgt_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sgt i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_sgt_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_sgt_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp sgt i128 %not, %x
+ ret i1 %cmp
+}
+; ~X s<= X --> X s> -1
+define i1 @src_sle_comm(i8 %x) {
+; CHECK-LABEL: @src_sle_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sle i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_sle_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_sle_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp sle i128 %not, %x
+ ret i1 %cmp
+}
+; ~X s>= X --> X s< 0
+define i1 @src_sge_comm(i8 %x) {
+; CHECK-LABEL: @src_sge_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp sge i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_sge_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_sge_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp sge i128 %not, %x
+ ret i1 %cmp
+}
+
+; X op ~X tests. op unsigned
+; X u< ~X --> X s> -1
+define i1 @src_ult(i8 %x) {
+; CHECK-LABEL: @src_ult(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ult i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_ult_i128(i128 %x) {
+; CHECK-LABEL: @src_ult_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ult i128 %x, %not
+ ret i1 %cmp
+}
+; X u> ~X --> X s< 0
+define i1 @src_ugt(i8 %x) {
+; CHECK-LABEL: @src_ugt(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ugt i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_ugt_i128(i128 %x) {
+; CHECK-LABEL: @src_ugt_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ugt i128 %x, %not
+ ret i1 %cmp
+}
+; X u<= ~X --> X s> -1
+define i1 @src_ule(i8 %x) {
+; CHECK-LABEL: @src_ule(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ule i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_ule_i128(i128 %x) {
+; CHECK-LABEL: @src_ule_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ule i128 %x, %not
+ ret i1 %cmp
+}
+; X u>= ~X --> X s< 0
+define i1 @src_uge(i8 %x) {
+; CHECK-LABEL: @src_uge(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp uge i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_uge_i128(i128 %x) {
+; CHECK-LABEL: @src_uge_i128(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp uge i128 %x, %not
+ ret i1 %cmp
+}
+; X op ~X tests. op unsigned. commutative
+; ~X u< X --> X s< 0
+define i1 @src_ult_comm(i8 %x) {
+; CHECK-LABEL: @src_ult_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ult i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_ult_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_ult_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ult i128 %not, %x
+ ret i1 %cmp
+}
+; ~X u> X --> X s> -1
+define i1 @src_ugt_comm(i8 %x) {
+; CHECK-LABEL: @src_ugt_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ugt i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_ugt_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_ugt_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ugt i128 %not, %x
+ ret i1 %cmp
+}
+; ~X u<= X --> X s< 0
+define i1 @src_ule_comm(i8 %x) {
+; CHECK-LABEL: @src_ule_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ule i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_ule_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_ule_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[X:%.*]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ule i128 %not, %x
+ ret i1 %cmp
+}
+; ~X u>= X --> X s> -1
+define i1 @src_uge_comm(i8 %x) {
+; CHECK-LABEL: @src_uge_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp uge i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_uge_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_uge_i128_comm(
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i128 [[X:%.*]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp uge i128 %not, %x
+ ret i1 %cmp
+}
+
+; X op ~X tests. euqality
+; X == ~X -> false
+define i1 @src_eq(i8 %x) {
+; CHECK-LABEL: @src_eq(
+; CHECK-NEXT: ret i1 false
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp eq i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_eq_i128(i128 %x) {
+; CHECK-LABEL: @src_eq_i128(
+; CHECK-NEXT: ret i1 false
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp eq i128 %x, %not
+ ret i1 %cmp
+}
+; X != ~X -> true
+define i1 @src_ne(i8 %x) {
+; CHECK-LABEL: @src_ne(
+; CHECK-NEXT: ret i1 true
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ne i8 %x, %not
+ ret i1 %cmp
+}
+define i1 @src_ne_i128(i128 %x) {
+; CHECK-LABEL: @src_ne_i128(
+; CHECK-NEXT: ret i1 true
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ne i128 %x, %not
+ ret i1 %cmp
+}
+
+; X op ~X tests. euqality. commutative
+; ~X == X -> false
+define i1 @src_eq_comm(i8 %x) {
+; CHECK-LABEL: @src_eq_comm(
+; CHECK-NEXT: ret i1 false
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp eq i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_eq_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_eq_i128_comm(
+; CHECK-NEXT: ret i1 false
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp eq i128 %not, %x
+ ret i1 %cmp
+}
+; ~X != X -> true
+define i1 @src_ne_comm(i8 %x) {
+; CHECK-LABEL: @src_ne_comm(
+; CHECK-NEXT: ret i1 true
+;
+ %not = xor i8 %x, -1
+ %cmp = icmp ne i8 %not, %x
+ ret i1 %cmp
+}
+define i1 @src_ne_i128_comm(i128 %x) {
+; CHECK-LABEL: @src_ne_i128_comm(
+; CHECK-NEXT: ret i1 true
+;
+ %not = xor i128 %x, -1
+ %cmp = icmp ne i128 %not, %x
+ ret i1 %cmp
+}
+
+; X op ~X tests. negative
+; X op Y
+define i1 @src_sle_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sle_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sle i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_sle_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sle_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sle i8 %y.not, %x
+ ret i1 %cmp
+}
+define i1 @src_sge_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sge_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sge i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_sge_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_sge_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp sge i8 %y.not, %x
+ ret i1 %cmp
+}
+define i1 @src_ule_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_ule_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp ule i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_ule_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_ule_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp ule i8 %y.not, %x
+ ret i1 %cmp
+}
+define i1 @src_uge_xny(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_uge_xny(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp uge i8 %x, %y.not
+ ret i1 %cmp
+}
+define i1 @src_uge_nyx(i8 %x, i8 %y) {
+; CHECK-LABEL: @src_uge_nyx(
+; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[Y_NOT]], [[X:%.*]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %y.not = xor i8 %y, -1
+ %cmp = icmp uge i8 %y.not, %x
+ ret i1 %cmp
+}
+
+; X op ~X tests. negative
+; (X+1) op ~X
+define i1 @src_sle_incx_nx(i8 %x) {
+; CHECK-LABEL: @src_sle_incx_nx(
+; CHECK-NEXT: [[TMP1:%.*]] = sub i8 -2, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[TMP1]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %nx = xor i8 %x, -1
+ %inc.x = add i8 %x, 1
+ %cmp = icmp sle i8 %inc.x, %nx
+ ret i1 %cmp
+}
+; (X-1) op ~X
+define i1 @src_sle_decx_nx(i8 %x) {
+; CHECK-LABEL: @src_sle_decx_nx(
+; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[TMP1]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %nx = xor i8 %x, -1
+ %dec.x = add i8 %x, -1
+ %cmp = icmp sle i8 %dec.x, %nx
+ ret i1 %cmp
+}
+; X op ~(X+1)
+define i1 @src_sle_x_nincx(i8 %x) {
+; CHECK-LABEL: @src_sle_x_nincx(
+; CHECK-NEXT: [[NOT_INC_X:%.*]] = sub i8 -2, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[NOT_INC_X]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %inc.x = add i8 %x, 1
+ %not.inc.x = xor i8 %inc.x, -1
+ %cmp = icmp sle i8 %x, %not.inc.x
+ ret i1 %cmp
+}
+; X op ~(X-1)
+define i1 @src_sle_x_ndecx(i8 %x) {
+; CHECK-LABEL: @src_sle_x_ndecx(
+; CHECK-NEXT: [[NOT_DEC_X:%.*]] = sub i8 0, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[NOT_DEC_X]], [[X]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %dec.x = add i8 %x, -1
+ %not.dec.x = xor i8 %dec.x, -1
+ %cmp = icmp sle i8 %x, %not.dec.x
+ ret i1 %cmp
+}
+
; test for (~x ^ y) < ~z
define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @test_xor1(
>From 5738bb7ebf89f1cd166cb8e626855fe58b332d31 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 1 Dec 2023 06:32:35 +0900
Subject: [PATCH 2/2] [InstCombine] simplify `x (comp) ~x`
simplify compare between specific variable `X` and `NOT(X)`
Proof: https://alive2.llvm.org/ce/z/eW-L_G
Fixed #57532.
---
.../InstCombine/InstCombineCompares.cpp | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index e42e011bd43615..0a29e693ac7188 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7058,6 +7058,45 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
}
}
+ // Transform X s< ~X --> X s< 0
+ // X s> ~X --> X s> -1
+ // X s>= ~X --> X s> -1
+ // X s<= ~X --> X s< 0
+ // X u< ~X --> X s> -1
+ // X u> ~X --> X s< 0
+ // X u<= ~X --> X s> -1
+ // X u>= ~X --> X s< 0
+ // X == ~X --> false
+ // X != ~X --> true
+ if (match(&I, m_c_ICmp(Pred, m_Value(X), m_Not(m_Deferred(X))))) {
+ CmpInst::Predicate NewPred;
+ switch (Pred) {
+ case ICmpInst::ICMP_EQ:
+ return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+ case ICmpInst::ICMP_NE:
+ return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType()));
+ case ICmpInst::ICMP_UGT:
+ case ICmpInst::ICMP_UGE:
+ case ICmpInst::ICMP_ULT:
+ case ICmpInst::ICMP_ULE:
+ NewPred = CmpInst::getSwappedPredicate(
+ CmpInst::getSignedPredicate(CmpInst::getStrictPredicate(Pred)));
+ break;
+ case ICmpInst::ICMP_SGT:
+ case ICmpInst::ICMP_SGE:
+ case ICmpInst::ICMP_SLT:
+ case ICmpInst::ICMP_SLE:
+ NewPred = CmpInst::getStrictPredicate(Pred);
+ break;
+ default:
+ llvm_unreachable("not a valid predicate");
+ }
+ Constant *Const = NewPred == ICmpInst::ICMP_SLT
+ ? Constant::getNullValue(X->getType())
+ : Constant::getAllOnesValue(X->getType());
+ return new ICmpInst(NewPred, X, Const);
+ }
+
Instruction *AddI = nullptr;
if (match(&I, m_UAddWithOverflow(m_Value(X), m_Value(Y),
m_Instruction(AddI))) &&
More information about the llvm-commits
mailing list