[llvm] [InstCombine] Preserve flags for abs(X) * abs(X) and nabs(X) * nabs(X) (PR #88662)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 18 06:42:07 PDT 2024
https://github.com/AtariDreams updated https://github.com/llvm/llvm-project/pull/88662
>From 898b94804054fefc488ee19833d2384ce8ce4d8a Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sun, 14 Apr 2024 11:50:44 -0400
Subject: [PATCH 1/2] [InstCombine] Pre-commit tests (NFC)
---
.../InstCombine/mul-inseltpoison.ll | 43 +++++++++++
llvm/test/Transforms/InstCombine/mul.ll | 71 +++++++++++++++++++
2 files changed, 114 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
index f47c5577075cbd..cfa989ef6eb62f 100644
--- a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
@@ -915,6 +915,26 @@ define i32 @combine_mul_abs_intrin(i32 %x) {
ret i32 %mul
}
+define i32 @combine_mul_abs_intrin_nuw(i32 %x) {
+; CHECK-LABEL: @combine_mul_abs_intrin_nuw(
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: ret i32 [[MUL]]
+;
+ %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ %mul = mul nuw i32 %abs, %abs
+ ret i32 %mul
+}
+
+define i32 @combine_mul_abs_intrin_nsw(i32 %x) {
+; CHECK-LABEL: @combine_mul_abs_intrin_nsw(
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: ret i32 [[MUL]]
+;
+ %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ %mul = mul nsw i32 %abs, %abs
+ ret i32 %mul
+}
+
define i32 @combine_mul_nabs_intrin(i32 %x) {
; CHECK-LABEL: @combine_mul_nabs_intrin(
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
@@ -926,6 +946,29 @@ define i32 @combine_mul_nabs_intrin(i32 %x) {
ret i32 %mul
}
+define i32 @combine_mul_nabs_intrin_nuw(i32 %x) {
+; CHECK-LABEL: @combine_mul_nabs_intrin_nuw(
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: ret i32 [[MUL]]
+;
+ %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ %neg = sub i32 0, %abs
+ %mul = mul nuw i32 %neg, %neg
+ ret i32 %mul
+}
+
+define i32 @combine_mul_nabs_intrin_nsw(i32 %x) {
+; CHECK-LABEL: @combine_mul_nabs_intrin_nsw(
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: ret i32 [[MUL]]
+;
+ %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ %neg = sub i32 0, %abs
+ %mul = mul nsw i32 %neg, %neg
+ ret i32 %mul
+}
+
+
; z * splat(0) = splat(0), even for scalable vectors
define <vscale x 2 x i64> @mul_scalable_splat_zero(<vscale x 2 x i64> %z) {
; CHECK-LABEL: @mul_scalable_splat_zero(
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index 227ca4a6d5cfad..c06718f5f675fb 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1605,6 +1605,31 @@ define i32 @combine_mul_nabs_i32(i32 %0) {
ret i32 %m
}
+define i32 @combine_mul_nabs_i32_unsigned_wrap(i32 %0) {
+; CHECK-LABEL: @combine_mul_nabs_i32_unsigned_wrap(
+; CHECK-NEXT: [[M:%.*]] = mul i32 [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: ret i32 [[M]]
+;
+ %c = icmp slt i32 %0, 0
+ %s = sub nsw i32 0, %0
+ %r = select i1 %c, i32 %0, i32 %s
+ %m = mul nuw i32 %r, %r
+ ret i32 %m
+}
+
+define i32 @combine_mul_nabs_i32_signed_wrap(i32 %0) {
+; CHECK-LABEL: @combine_mul_nabs_i32_signed_wrap(
+; CHECK-NEXT: [[M:%.*]] = mul i32 [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: ret i32 [[M]]
+;
+ %c = icmp slt i32 %0, 0
+ %s = sub nsw i32 0, %0
+ %r = select i1 %c, i32 %0, i32 %s
+ %m = mul nsw i32 %r, %r
+ ret i32 %m
+}
+
+
define <4 x i32> @combine_mul_nabs_v4i32(<4 x i32> %0) {
; CHECK-LABEL: @combine_mul_nabs_v4i32(
; CHECK-NEXT: [[M:%.*]] = mul <4 x i32> [[TMP0:%.*]], [[TMP0]]
@@ -1617,6 +1642,30 @@ define <4 x i32> @combine_mul_nabs_v4i32(<4 x i32> %0) {
ret <4 x i32> %m
}
+define <4 x i32> @combine_mul_nabs_v4i32_unsigned_wrap(<4 x i32> %0) {
+; CHECK-LABEL: @combine_mul_nabs_v4i32_unsigned_wrap(
+; CHECK-NEXT: [[M:%.*]] = mul <4 x i32> [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: ret <4 x i32> [[M]]
+;
+ %c = icmp slt <4 x i32> %0, zeroinitializer
+ %s = sub nsw <4 x i32> zeroinitializer, %0
+ %r = select <4 x i1> %c, <4 x i32> %0, <4 x i32> %s
+ %m = mul nuw <4 x i32> %r, %r
+ ret <4 x i32> %m
+}
+
+define <4 x i32> @combine_mul_nabs_v4i32_signed_wrap(<4 x i32> %0) {
+; CHECK-LABEL: @combine_mul_nabs_v4i32_signed_wrap(
+; CHECK-NEXT: [[M:%.*]] = mul <4 x i32> [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: ret <4 x i32> [[M]]
+;
+ %c = icmp slt <4 x i32> %0, zeroinitializer
+ %s = sub nsw <4 x i32> zeroinitializer, %0
+ %r = select <4 x i1> %c, <4 x i32> %0, <4 x i32> %s
+ %m = mul nsw <4 x i32> %r, %r
+ ret <4 x i32> %m
+}
+
define i32 @combine_mul_abs_intrin(i32 %x) {
; CHECK-LABEL: @combine_mul_abs_intrin(
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
@@ -1638,6 +1687,28 @@ define i32 @combine_mul_nabs_intrin(i32 %x) {
ret i32 %mul
}
+define i32 @combine_mul_nabs_intrin_unsigned_flags(i32 %x) {
+; CHECK-LABEL: @combine_mul_nabs_intrin_unsigned_flags(
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: ret i32 [[MUL]]
+;
+ %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ %neg = sub i32 0, %abs
+ %mul = mul nuw i32 %neg, %neg
+ ret i32 %mul
+}
+
+define i32 @combine_mul_nabs_intrin_signed_flags(i32 %x) {
+; CHECK-LABEL: @combine_mul_nabs_intrin_signed_flags(
+; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: ret i32 [[MUL]]
+;
+ %abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ %neg = sub i32 0, %abs
+ %mul = mul nsw i32 %neg, %neg
+ ret i32 %mul
+}
+
; z * splat(0) = splat(0), even for scalable vectors
define <vscale x 2 x i64> @mul_scalable_splat_zero(<vscale x 2 x i64> %z) {
; CHECK-LABEL: @mul_scalable_splat_zero(
>From fe34af8b7c58ea609bd27f9832a73e9e70e536a2 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Sun, 14 Apr 2024 11:31:02 -0400
Subject: [PATCH 2/2] [InstCombine] Preserve flags for abs(X) * abs(X) and
nabs(X) * nabs(X)
Alive2 Proofs:
https://alive2.llvm.org/ce/z/CN9BP-
https://alive2.llvm.org/ce/z/kq9vh6
https://alive2.llvm.org/ce/z/LtVSL5
---
.../InstCombine/InstCombineMulDivRem.cpp | 20 ++++++++++++++++---
.../InstCombine/mul-inseltpoison.ll | 6 +++---
llvm/test/Transforms/InstCombine/mul.ll | 12 +++++------
3 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 53478e07394b2c..cfb097df6b6d0d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -319,9 +319,23 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
}
// abs(X) * abs(X) -> X * X
- Value *X;
- if (Op0 == Op1 && match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))))
- return BinaryOperator::CreateMul(X, X);
+ if (Op0 == Op1) {
+ Value *X;
+ // nabs(X) * nabs(X) -> X * X
+ if (match(Op0, m_Neg(m_Intrinsic<Intrinsic::abs>(m_Value(X))))) {
+ if (I.hasNoUnsignedWrap()) {
+ Instruction *NewMul = BinaryOperator::CreateNUWMul(X, X);
+ NewMul->setHasNoSignedWrap(true);
+ return NewMul;
+ }
+ return I.hasNoSignedWrap() ? BinaryOperator::CreateNSWMul(X, X)
+ : BinaryOperator::CreateMul(X, X);
+ }
+
+ if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))))
+ return I.hasNoSignedWrap() ? BinaryOperator::CreateNSWMul(X, X)
+ : BinaryOperator::CreateMul(X, X);
+ }
{
Value *Y;
diff --git a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
index cfa989ef6eb62f..5557772e0d2f38 100644
--- a/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/mul-inseltpoison.ll
@@ -927,7 +927,7 @@ define i32 @combine_mul_abs_intrin_nuw(i32 %x) {
define i32 @combine_mul_abs_intrin_nsw(i32 %x) {
; CHECK-LABEL: @combine_mul_abs_intrin_nsw(
-; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
; CHECK-NEXT: ret i32 [[MUL]]
;
%abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
@@ -948,7 +948,7 @@ define i32 @combine_mul_nabs_intrin(i32 %x) {
define i32 @combine_mul_nabs_intrin_nuw(i32 %x) {
; CHECK-LABEL: @combine_mul_nabs_intrin_nuw(
-; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[X:%.*]], [[X]]
; CHECK-NEXT: ret i32 [[MUL]]
;
%abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
@@ -959,7 +959,7 @@ define i32 @combine_mul_nabs_intrin_nuw(i32 %x) {
define i32 @combine_mul_nabs_intrin_nsw(i32 %x) {
; CHECK-LABEL: @combine_mul_nabs_intrin_nsw(
-; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
; CHECK-NEXT: ret i32 [[MUL]]
;
%abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll
index c06718f5f675fb..860ae7335ce8f9 100644
--- a/llvm/test/Transforms/InstCombine/mul.ll
+++ b/llvm/test/Transforms/InstCombine/mul.ll
@@ -1607,7 +1607,7 @@ define i32 @combine_mul_nabs_i32(i32 %0) {
define i32 @combine_mul_nabs_i32_unsigned_wrap(i32 %0) {
; CHECK-LABEL: @combine_mul_nabs_i32_unsigned_wrap(
-; CHECK-NEXT: [[M:%.*]] = mul i32 [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i32 [[TMP0:%.*]], [[TMP0]]
; CHECK-NEXT: ret i32 [[M]]
;
%c = icmp slt i32 %0, 0
@@ -1619,7 +1619,7 @@ define i32 @combine_mul_nabs_i32_unsigned_wrap(i32 %0) {
define i32 @combine_mul_nabs_i32_signed_wrap(i32 %0) {
; CHECK-LABEL: @combine_mul_nabs_i32_signed_wrap(
-; CHECK-NEXT: [[M:%.*]] = mul i32 [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: [[M:%.*]] = mul nsw i32 [[TMP0:%.*]], [[TMP0]]
; CHECK-NEXT: ret i32 [[M]]
;
%c = icmp slt i32 %0, 0
@@ -1644,7 +1644,7 @@ define <4 x i32> @combine_mul_nabs_v4i32(<4 x i32> %0) {
define <4 x i32> @combine_mul_nabs_v4i32_unsigned_wrap(<4 x i32> %0) {
; CHECK-LABEL: @combine_mul_nabs_v4i32_unsigned_wrap(
-; CHECK-NEXT: [[M:%.*]] = mul <4 x i32> [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: [[M:%.*]] = mul nuw nsw <4 x i32> [[TMP0:%.*]], [[TMP0]]
; CHECK-NEXT: ret <4 x i32> [[M]]
;
%c = icmp slt <4 x i32> %0, zeroinitializer
@@ -1656,7 +1656,7 @@ define <4 x i32> @combine_mul_nabs_v4i32_unsigned_wrap(<4 x i32> %0) {
define <4 x i32> @combine_mul_nabs_v4i32_signed_wrap(<4 x i32> %0) {
; CHECK-LABEL: @combine_mul_nabs_v4i32_signed_wrap(
-; CHECK-NEXT: [[M:%.*]] = mul <4 x i32> [[TMP0:%.*]], [[TMP0]]
+; CHECK-NEXT: [[M:%.*]] = mul nsw <4 x i32> [[TMP0:%.*]], [[TMP0]]
; CHECK-NEXT: ret <4 x i32> [[M]]
;
%c = icmp slt <4 x i32> %0, zeroinitializer
@@ -1689,7 +1689,7 @@ define i32 @combine_mul_nabs_intrin(i32 %x) {
define i32 @combine_mul_nabs_intrin_unsigned_flags(i32 %x) {
; CHECK-LABEL: @combine_mul_nabs_intrin_unsigned_flags(
-; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[X:%.*]], [[X]]
; CHECK-NEXT: ret i32 [[MUL]]
;
%abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
@@ -1700,7 +1700,7 @@ define i32 @combine_mul_nabs_intrin_unsigned_flags(i32 %x) {
define i32 @combine_mul_nabs_intrin_signed_flags(i32 %x) {
; CHECK-LABEL: @combine_mul_nabs_intrin_signed_flags(
-; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[X:%.*]], [[X]]
; CHECK-NEXT: ret i32 [[MUL]]
;
%abs = call i32 @llvm.abs.i32(i32 %x, i1 false)
More information about the llvm-commits
mailing list