[llvm] [ConstantFold][RFC] Fold special constant value with binop absorber f… (PR #109736)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 23 17:54:57 PDT 2024
https://github.com/eric-xtang1008 updated https://github.com/llvm/llvm-project/pull/109736
>From 87dd67fccde45793f70e8b71785d55c1ff3b0134 Mon Sep 17 00:00:00 2001
From: "eric.tang" <eric.tang at starfivetech.com>
Date: Mon, 23 Sep 2024 10:27:59 +0800
Subject: [PATCH] [ConstantFold][RFC] Fold special constant value with binop
absorber folding
Return the consant value C if C op X = C, X can be every
value including undef and poison vaule, and remove redurdant
flods later in the code.
Signed-off-by: eric.tang <eric.tang at starfivetech.com>
---
llvm/include/llvm/IR/Constants.h | 7 ++--
llvm/lib/IR/ConstantFold.cpp | 35 ++++++++-----------
llvm/lib/IR/Constants.cpp | 25 +++++++++----
.../InstCombine/vec_shuffle-inseltpoison.ll | 16 +++++----
.../Transforms/InstCombine/vec_shuffle.ll | 16 +++++----
llvm/test/Transforms/InstSimplify/undef.ll | 6 ++--
.../X86/insert-binop-inseltpoison.ll | 2 +-
7 files changed, 62 insertions(+), 45 deletions(-)
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 3b16aa039a5087..18e92dcef448ce 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -1210,8 +1210,11 @@ class ConstantExpr : public Constant {
/// Return the absorbing element for the given binary
/// operation, i.e. a constant C such that X op C = C and C op X = C for
/// every X. For example, this returns zero for integer multiplication.
- /// It returns null if the operator doesn't have an absorbing element.
- static Constant *getBinOpAbsorber(unsigned Opcode, Type *Ty);
+ /// If AllowLHSConstant is true, operand 0 is a constant C that must be
+ /// defined as C op X = C. It returns null if the operator doesn't have
+ /// an absorbing element.
+ static Constant *getBinOpAbsorber(unsigned Opcode, Type *Ty,
+ bool AllowLHSConstant = false);
/// Transparently provide more efficient getOperand methods.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant);
diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index 05ab0968ef6f39..331decc51d4f29 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -624,6 +624,14 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
return C1;
}
+ if (Constant *Absorber = ConstantExpr::getBinOpAbsorber(
+ Opcode, C1->getType(), /*AllowLHSAbsorber*/ true)) {
+ if (C1 == Absorber)
+ return C1;
+ if (C2 == Absorber)
+ return C2;
+ }
+
// Binary operations propagate poison.
if (isa<PoisonValue>(C1) || isa<PoisonValue>(C2))
return PoisonValue::get(C1->getType());
@@ -733,8 +741,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
if (ConstantInt *CI2 = dyn_cast<ConstantInt>(C2)) {
switch (Opcode) {
case Instruction::Mul:
- if (CI2->isZero())
- return C2; // X * 0 == 0
+ assert(!CI2->isZero() && "Mul zero handled above");
break;
case Instruction::UDiv:
case Instruction::SDiv:
@@ -749,9 +756,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
return PoisonValue::get(CI2->getType()); // X % 0 == poison
break;
case Instruction::And:
- if (CI2->isZero())
- return C2; // X & 0 == 0
-
+ assert(!CI2->isZero() && "And zero handled above");
if (ConstantExpr *CE1 = dyn_cast<ConstantExpr>(C1)) {
// If and'ing the address of a global with a constant, fold it.
if (CE1->getOpcode() == Instruction::PtrToInt &&
@@ -792,8 +797,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
}
break;
case Instruction::Or:
- if (CI2->isMinusOne())
- return C2; // X | -1 == -1
+ assert(!CI2->isMinusOne() && "Or MinusOne handled above");
break;
}
} else if (isa<ConstantInt>(C1)) {
@@ -840,33 +844,22 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
case Instruction::Xor:
return ConstantInt::get(CI1->getContext(), C1V ^ C2V);
case Instruction::Shl:
+ assert(!CI1->isZero() && "Zero Shl handled above");
if (C2V.ult(C1V.getBitWidth()))
return ConstantInt::get(CI1->getContext(), C1V.shl(C2V));
return PoisonValue::get(C1->getType()); // too big shift is poison
case Instruction::LShr:
+ assert(!CI1->isZero() && "Zero LShr handled above");
if (C2V.ult(C1V.getBitWidth()))
return ConstantInt::get(CI1->getContext(), C1V.lshr(C2V));
return PoisonValue::get(C1->getType()); // too big shift is poison
case Instruction::AShr:
+ assert(!CI1->isZero() && "Zero AShr handled above");
if (C2V.ult(C1V.getBitWidth()))
return ConstantInt::get(CI1->getContext(), C1V.ashr(C2V));
return PoisonValue::get(C1->getType()); // too big shift is poison
}
}
-
- switch (Opcode) {
- case Instruction::SDiv:
- case Instruction::UDiv:
- case Instruction::URem:
- case Instruction::SRem:
- case Instruction::LShr:
- case Instruction::AShr:
- case Instruction::Shl:
- if (CI1->isZero()) return C1;
- break;
- default:
- break;
- }
} else if (ConstantFP *CFP1 = dyn_cast<ConstantFP>(C1)) {
if (ConstantFP *CFP2 = dyn_cast<ConstantFP>(C2)) {
const APFloat &C1V = CFP1->getValueAPF();
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index d6c00a4b547829..bfa2d3ae5b9091 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -2735,17 +2735,30 @@ Constant *ConstantExpr::getIdentity(Instruction *I, Type *Ty,
return nullptr;
}
-Constant *ConstantExpr::getBinOpAbsorber(unsigned Opcode, Type *Ty) {
+Constant *ConstantExpr::getBinOpAbsorber(unsigned Opcode, Type *Ty,
+ bool AllowLHSConstant) {
switch (Opcode) {
default:
- // Doesn't have an absorber.
- return nullptr;
+ break;
- case Instruction::Or:
+ case Instruction::Or: // -1 | X = -1
return Constant::getAllOnesValue(Ty);
- case Instruction::And:
- case Instruction::Mul:
+ case Instruction::And: // 0 & X = 0
+ case Instruction::Mul: // 0 * X = 0
+ return Constant::getNullValue(Ty);
+ }
+
+ // AllowLHSConstant must be set.
+ if (!AllowLHSConstant)
+ return nullptr;
+
+ switch (Opcode) {
+ default:
+ return nullptr;
+ case Instruction::Shl: // 0 << X = 0
+ case Instruction::LShr: // 0 >>l X = 0
+ case Instruction::AShr: // 0 >>a X = 0
return Constant::getNullValue(Ty);
}
}
diff --git a/llvm/test/Transforms/InstCombine/vec_shuffle-inseltpoison.ll b/llvm/test/Transforms/InstCombine/vec_shuffle-inseltpoison.ll
index 0f233fbb4729e6..c5f276ec908397 100644
--- a/llvm/test/Transforms/InstCombine/vec_shuffle-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/vec_shuffle-inseltpoison.ll
@@ -691,8 +691,8 @@ define <4 x i16> @widening_shuffle_shl_constant_op1_non0(<2 x i16> %v) {
define <4 x i16> @widening_shuffle_or(<2 x i16> %v) {
; CHECK-LABEL: @widening_shuffle_or(
-; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i16> [[V:%.*]], <i16 42, i16 -42>
-; CHECK-NEXT: [[BO:%.*]] = shufflevector <2 x i16> [[TMP1]], <2 x i16> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <2 x i16> [[V:%.*]], <2 x i16> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[BO:%.*]] = or <4 x i16> [[SHUF]], <i16 42, i16 -42, i16 -1, i16 -1>
; CHECK-NEXT: ret <4 x i16> [[BO]]
;
%shuf = shufflevector <2 x i16> %v, <2 x i16> poison, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
@@ -1035,7 +1035,8 @@ define <2 x i32> @and_splat_constant(<2 x i32> %x) {
define <4 x i16> @and_constant_mask_poison(<4 x i16> %add) {
; CHECK-LABEL: @and_constant_mask_poison(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], <i16 0, i16 0, i16 -1, i16 -1>
; CHECK-NEXT: ret <4 x i16> [[AND]]
;
entry:
@@ -1047,7 +1048,8 @@ entry:
define <4 x i16> @and_constant_mask_poison_2(<4 x i16> %add) {
; CHECK-LABEL: @and_constant_mask_poison_2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 1, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 1, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], <i16 -1, i16 -1, i16 -1, i16 0>
; CHECK-NEXT: ret <4 x i16> [[AND]]
;
entry:
@@ -1098,7 +1100,8 @@ entry:
define <4 x i16> @or_constant_mask_poison(<4 x i16> %in) {
; CHECK-LABEL: @or_constant_mask_poison(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], <i16 -1, i16 -1, i16 0, i16 0>
; CHECK-NEXT: ret <4 x i16> [[OR]]
;
entry:
@@ -1110,7 +1113,8 @@ entry:
define <4 x i16> @or_constant_mask_poison_2(<4 x i16> %in) {
; CHECK-LABEL: @or_constant_mask_poison_2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], <i16 -1, i16 0, i16 0, i16 -1>
; CHECK-NEXT: ret <4 x i16> [[OR]]
;
entry:
diff --git a/llvm/test/Transforms/InstCombine/vec_shuffle.ll b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
index 75a84e51279b80..aaa46a0dfcd151 100644
--- a/llvm/test/Transforms/InstCombine/vec_shuffle.ll
+++ b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
@@ -685,8 +685,8 @@ define <4 x i16> @widening_shuffle_shl_constant_op1_non0(<2 x i16> %v) {
define <4 x i16> @widening_shuffle_or(<2 x i16> %v) {
; CHECK-LABEL: @widening_shuffle_or(
-; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i16> [[V:%.*]], <i16 42, i16 -42>
-; CHECK-NEXT: [[BO:%.*]] = shufflevector <2 x i16> [[TMP1]], <2 x i16> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <2 x i16> [[V:%.*]], <2 x i16> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[BO:%.*]] = or <4 x i16> [[SHUF]], <i16 42, i16 -42, i16 -1, i16 -1>
; CHECK-NEXT: ret <4 x i16> [[BO]]
;
%shuf = shufflevector <2 x i16> %v, <2 x i16> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
@@ -1029,7 +1029,8 @@ define <2 x i32> @and_splat_constant(<2 x i32> %x) {
define <4 x i16> @and_constant_mask_poison(<4 x i16> %add) {
; CHECK-LABEL: @and_constant_mask_poison(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], <i16 0, i16 0, i16 -1, i16 -1>
; CHECK-NEXT: ret <4 x i16> [[AND]]
;
entry:
@@ -1041,7 +1042,8 @@ entry:
define <4 x i16> @and_constant_mask_poison_2(<4 x i16> %add) {
; CHECK-LABEL: @and_constant_mask_poison_2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 1, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> poison, <4 x i32> <i32 1, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], <i16 -1, i16 -1, i16 -1, i16 0>
; CHECK-NEXT: ret <4 x i16> [[AND]]
;
entry:
@@ -1092,7 +1094,8 @@ entry:
define <4 x i16> @or_constant_mask_poison(<4 x i16> %in) {
; CHECK-LABEL: @or_constant_mask_poison(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 poison, i32 1, i32 1>
+; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], <i16 -1, i16 -1, i16 0, i16 0>
; CHECK-NEXT: ret <4 x i16> [[OR]]
;
entry:
@@ -1104,7 +1107,8 @@ entry:
define <4 x i16> @or_constant_mask_poison_2(<4 x i16> %in) {
; CHECK-LABEL: @or_constant_mask_poison_2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> poison, <4 x i32> <i32 poison, i32 1, i32 1, i32 poison>
+; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], <i16 -1, i16 0, i16 0, i16 -1>
; CHECK-NEXT: ret <4 x i16> [[OR]]
;
entry:
diff --git a/llvm/test/Transforms/InstSimplify/undef.ll b/llvm/test/Transforms/InstSimplify/undef.ll
index b32744fe8a3bb1..fee4372b31a22f 100644
--- a/llvm/test/Transforms/InstSimplify/undef.ll
+++ b/llvm/test/Transforms/InstSimplify/undef.ll
@@ -244,7 +244,7 @@ define i32 @test24() {
define i32 @test25() {
; CHECK-LABEL: @test25(
-; CHECK-NEXT: ret i32 poison
+; CHECK-NEXT: ret i32 0
;
%b = lshr i32 0, undef
ret i32 %b
@@ -252,7 +252,7 @@ define i32 @test25() {
define i32 @test26() {
; CHECK-LABEL: @test26(
-; CHECK-NEXT: ret i32 poison
+; CHECK-NEXT: ret i32 0
;
%b = ashr i32 0, undef
ret i32 %b
@@ -260,7 +260,7 @@ define i32 @test26() {
define i32 @test27() {
; CHECK-LABEL: @test27(
-; CHECK-NEXT: ret i32 poison
+; CHECK-NEXT: ret i32 0
;
%b = shl i32 0, undef
ret i32 %b
diff --git a/llvm/test/Transforms/VectorCombine/X86/insert-binop-inseltpoison.ll b/llvm/test/Transforms/VectorCombine/X86/insert-binop-inseltpoison.ll
index c1100780254c18..d3863a274a9dd4 100644
--- a/llvm/test/Transforms/VectorCombine/X86/insert-binop-inseltpoison.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/insert-binop-inseltpoison.ll
@@ -100,7 +100,7 @@ define <16 x i8> @ins1_ins0_add(i8 %x, i8 %y) {
define <4 x i32> @ins0_ins0_mul(i32 %x, i32 %y) {
; CHECK-LABEL: @ins0_ins0_mul(
; CHECK-NEXT: [[R_SCALAR:%.*]] = mul i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[R:%.*]] = insertelement <4 x i32> poison, i32 [[R_SCALAR]], i64 0
+; CHECK-NEXT: [[R:%.*]] = insertelement <4 x i32> zeroinitializer, i32 [[R_SCALAR]], i64 0
; CHECK-NEXT: ret <4 x i32> [[R]]
;
%i0 = insertelement <4 x i32> zeroinitializer, i32 %x, i32 0
More information about the llvm-commits
mailing list