[llvm] instcombine (PR #69882)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 22 08:10:24 PDT 2023
https://github.com/elhewaty created https://github.com/llvm/llvm-project/pull/69882
- [InstCombine] Add test coverage for comparisons of operands including one-complemented oparands(NFC).
- [InstCombine] Fold xored one-complemented operand comparisons.
>From 52f74973cd095ddee69913d6835e9c8c526d3fb5 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 22 Oct 2023 12:11:21 +0300
Subject: [PATCH 1/2] [InstCombine] Add test coverage for comparisons of
operands including one-complemented oparands(NFC).
---
.../Transforms/InstCombine/icmp-of-xor-x.ll | 120 ++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 9b6572697cf5e8f..6e17443807ae25a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -4,6 +4,126 @@
declare void @llvm.assume(i1)
declare void @barrier()
+define i32 @test_slt_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_slt_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp slt i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_sle_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_sle_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp sle i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_sgt_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_sgt_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp sgt i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_sge_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_sge_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp sge i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_ult_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_ult_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp ult i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_ule_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_ule_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp ule i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_ugt_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_ugt_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp ugt i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
+define i32 @test_uge_xor(i32 %0, i32 %1) {
+; CHECK-LABEL: @test_uge_xor(
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
+; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
+; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
+; CHECK-NEXT: ret i32 [[TMP6]]
+;
+ %3 = xor i32 %0, -1
+ %4 = xor i32 %3, %1
+ %5 = icmp uge i32 %4, %3
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+}
+
define i1 @xor_uge(i8 %x, i8 %y) {
; CHECK-LABEL: @xor_uge(
; CHECK-NEXT: [[YNZ:%.*]] = icmp ne i8 [[Y:%.*]], 0
>From 1a4e700abfa7c9b84c9817cf95f33f0d69dffc53 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sun, 22 Oct 2023 18:07:40 +0300
Subject: [PATCH 2/2] [InstCombine] Fold xored one-complemented operand
comparisons.
---
.../InstCombine/InstCombineCompares.cpp | 29 ++++++++
.../Transforms/InstCombine/icmp-of-xor-x.ll | 72 +++++++++----------
2 files changed, 61 insertions(+), 40 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 66e2b6c72cce46c..4c19edfb27d2f2b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6929,6 +6929,23 @@ static Instruction *foldReductionIdiom(ICmpInst &I,
return nullptr;
}
+// Gets the inverse of the predicate, but not the full predicate,
+// it doesn't change the equality, e.g SLE <-> SGE, SLT <-> SGT,
+// ULE <-> UGE, ULT <-> UGT
+static ICmpInst::Predicate ConvertPred(ICmpInst::Predicate Pred) {
+ switch(Pred) {
+ case ICmpInst::ICMP_SLE: return ICmpInst::ICMP_SGE;
+ case ICmpInst::ICMP_SGE: return ICmpInst::ICMP_SLE;
+ case ICmpInst::ICMP_SLT: return ICmpInst::ICMP_SGT;
+ case ICmpInst::ICMP_SGT: return ICmpInst::ICMP_SLT;
+ case ICmpInst::ICMP_ULE: return ICmpInst::ICMP_UGE;
+ case ICmpInst::ICMP_UGE: return ICmpInst::ICMP_ULE;
+ case ICmpInst::ICMP_ULT: return ICmpInst::ICMP_UGT;
+ case ICmpInst::ICMP_UGT: return ICmpInst::ICMP_ULT;
+ default: llvm_unreachable("Invalid Predicate");
+ }
+}
+
Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
bool Changed = false;
const SimplifyQuery Q = SQ.getWithInstruction(&I);
@@ -7127,6 +7144,18 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
return new ICmpInst(I.getInversePredicate(), Builder.CreateAnd(A, B),
Op1);
+ // Transform (~A ^ B) s< ~A --> (A ^ B) s> A,
+ // (~A ^ B) s> ~A --> (A ^ B) s< A,
+ // (~A ^ B) s<= ~A --> (A ^ B) s>= A,
+ // (~A ^ B) s>= ~A --> (A ^ B) s<= A,
+ // (~A ^ B) u< ~A --> (A ^ B) u< A,
+ // (~A ^ B) u> ~A --> (A ^ B) u< A,
+ // (~A ^ B) u<= ~A --> (A ^ B) u>= A,
+ // and (~A ^ B) u>= ~A --> (A ^ B) <= A
+ if (match(Op0, m_Xor(m_Not(m_Value(A)), m_Value(B))) &&
+ match(Op1, m_Not(m_Value(A))) && !I.isEquality())
+ return new ICmpInst(ConvertPred(Pred), Builder.CreateXor(A, B), A);
+
// ~X < ~Y --> Y < X
// ~X < C --> X > ~C
if (match(Op0, m_Not(m_Value(A)))) {
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index 6e17443807ae25a..893fb868e6adc77 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -6,11 +6,10 @@ declare void @barrier()
define i32 @test_slt_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_slt_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp slt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -21,11 +20,10 @@ define i32 @test_slt_xor(i32 %0, i32 %1) {
define i32 @test_sle_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_sle_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp sle i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp sge i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -36,11 +34,10 @@ define i32 @test_sle_xor(i32 %0, i32 %1) {
define i32 @test_sgt_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_sgt_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp slt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -51,11 +48,10 @@ define i32 @test_sgt_xor(i32 %0, i32 %1) {
define i32 @test_sge_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_sge_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp sge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp sle i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -66,11 +62,10 @@ define i32 @test_sge_xor(i32 %0, i32 %1) {
define i32 @test_ult_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_ult_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ugt i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -81,11 +76,10 @@ define i32 @test_ult_xor(i32 %0, i32 %1) {
define i32 @test_ule_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_ule_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp ule i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp uge i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -96,11 +90,10 @@ define i32 @test_ule_xor(i32 %0, i32 %1) {
define i32 @test_ugt_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_ugt_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
@@ -111,11 +104,10 @@ define i32 @test_ugt_xor(i32 %0, i32 %1) {
define i32 @test_uge_xor(i32 %0, i32 %1) {
; CHECK-LABEL: @test_uge_xor(
-; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], -1
-; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], [[TMP1:%.*]]
-; CHECK-NEXT: [[TMP5:%.*]] = icmp uge i32 [[TMP4]], [[TMP3]]
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
-; CHECK-NEXT: ret i32 [[TMP6]]
+; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[TMP3]], [[TMP0]]
+; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP4]] to i32
+; CHECK-NEXT: ret i32 [[TMP5]]
;
%3 = xor i32 %0, -1
%4 = xor i32 %3, %1
More information about the llvm-commits
mailing list