summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/IR/ConstantFold.cpp13
-rw-r--r--llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll8
-rw-r--r--llvm/test/Transforms/InstCombine/vec_shuffle.ll24
3 files changed, 27 insertions, 18 deletions
diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
index a6cd8331008..f6dbe9b5ea9 100644
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -988,6 +988,19 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1,
Constant *C2) {
assert(Instruction::isBinaryOp(Opcode) && "Non-binary instruction detected");
+ // Simplify BinOps with their identity values first. They are no-ops and we
+ // can always return the other value, including undef or poison values.
+ // FIXME: remove unnecessary duplicated identity patterns below.
+ // FIXME: Use AllowRHSConstant with getBinOpIdentity to handle additional ops,
+ // like X << 0 = X.
+ Constant *Identity = ConstantExpr::getBinOpIdentity(Opcode, C1->getType());
+ if (Identity) {
+ if (C1 == Identity)
+ return C2;
+ if (C2 == Identity)
+ return C1;
+ }
+
// Handle scalar UndefValue. Vectors are always evaluated per element.
bool HasScalarUndef = !C1->getType()->isVectorTy() &&
(isa<UndefValue>(C1) || isa<UndefValue>(C2));
diff --git a/llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll b/llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll
index 7bb824dfb46..68307892187 100644
--- a/llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll
+++ b/llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll
@@ -3,7 +3,7 @@
define i32 @and1() {
; CHECK-LABEL: @and1(
-; CHECK-NEXT: ret i32 0
+; CHECK-NEXT: ret i32 undef
;
%r = and i32 undef, -1
ret i32 %r
@@ -11,7 +11,7 @@ define i32 @and1() {
define i32 @and2() {
; CHECK-LABEL: @and2(
-; CHECK-NEXT: ret i32 0
+; CHECK-NEXT: ret i32 undef
;
%r = and i32 -1, undef
ret i32 %r
@@ -27,7 +27,7 @@ define i32 @and3_no_identity() {
define i32 @or1() {
; CHECK-LABEL: @or1(
-; CHECK-NEXT: ret i32 -1
+; CHECK-NEXT: ret i32 undef
;
%r = or i32 0, undef
ret i32 %r
@@ -35,7 +35,7 @@ define i32 @or1() {
define i32 @or2() {
; CHECK-LABEL: @or2(
-; CHECK-NEXT: ret i32 -1
+; CHECK-NEXT: ret i32 undef
;
%r = or i32 undef, 0
ret i32 %r
diff --git a/llvm/test/Transforms/InstCombine/vec_shuffle.ll b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
index 07c888ac6ae..b7b02a597d2 100644
--- a/llvm/test/Transforms/InstCombine/vec_shuffle.ll
+++ b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
@@ -1034,13 +1034,11 @@ entry:
ret <4 x i16> %and
}
-; FIXME: We should be able to move the AND across the shuffle, as -1 (AND identity value) is used for undef lanes.
+; We can move the AND across the shuffle, as -1 (AND identity value) is used for undef lanes.
define <4 x i16> @and_constant_mask_undef_3(<4 x i16> %add) {
; CHECK-LABEL: @and_constant_mask_undef_3(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> undef, <4 x i32> <i32 0, i32 1, i32 1, i32 undef>
-; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], <i16 0, i16 0, i16 0, i16 -1>
-; CHECK-NEXT: ret <4 x i16> [[AND]]
+; CHECK-NEXT: ret <4 x i16> <i16 0, i16 0, i16 0, i16 undef>
;
entry:
%shuffle = shufflevector <4 x i16> %add, <4 x i16> undef, <4 x i32> <i32 0, i32 1, i32 1, i32 undef>
@@ -1048,12 +1046,12 @@ entry:
ret <4 x i16> %and
}
-; FIXME: We should be able to move the AND across the shuffle, as -1 (AND identity value) is used for undef lanes.
+; We can move the AND across the shuffle, as -1 (AND identity value) is used for undef lanes.
define <4 x i16> @and_constant_mask_undef_4(<4 x i16> %add) {
; CHECK-LABEL: @and_constant_mask_undef_4(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[ADD:%.*]], <4 x i16> undef, <4 x i32> <i32 0, i32 1, i32 1, i32 undef>
-; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], <i16 9, i16 20, i16 20, i16 -1>
+; CHECK-NEXT: [[TMP0:%.*]] = and <4 x i16> [[ADD:%.*]], <i16 9, i16 20, i16 undef, i16 undef>
+; CHECK-NEXT: [[AND:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> undef, <4 x i32> <i32 0, i32 1, i32 1, i32 undef>
; CHECK-NEXT: ret <4 x i16> [[AND]]
;
entry:
@@ -1105,13 +1103,11 @@ entry:
ret <4 x i16> %or
}
-; FIXME: We should be able to move the OR across the shuffle, as 0 (OR identity value) is used for undef lanes.
+; We can move the OR across the shuffle, as 0 (OR identity value) is used for undef lanes.
define <4 x i16> @or_constant_mask_undef_3(<4 x i16> %in) {
; CHECK-LABEL: @or_constant_mask_undef_3(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> undef, <4 x i32> <i32 undef, i32 1, i32 1, i32 undef>
-; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], <i16 0, i16 -1, i16 -1, i16 0>
-; CHECK-NEXT: ret <4 x i16> [[OR]]
+; CHECK-NEXT: ret <4 x i16> <i16 undef, i16 -1, i16 -1, i16 undef>
;
entry:
%shuffle = shufflevector <4 x i16> %in, <4 x i16> undef, <4 x i32> <i32 undef, i32 1, i32 1, i32 undef>
@@ -1119,12 +1115,12 @@ entry:
ret <4 x i16> %or
}
-; FIXME: We should be able to move the OR across the shuffle, as 0 (OR identity value) is used for undef lanes.
+; We can move the OR across the shuffle, as 0 (OR identity value) is used for undef lanes.
define <4 x i16> @or_constant_mask_undef_4(<4 x i16> %in) {
; CHECK-LABEL: @or_constant_mask_undef_4(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <4 x i16> [[IN:%.*]], <4 x i16> undef, <4 x i32> <i32 undef, i32 1, i32 1, i32 undef>
-; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], <i16 0, i16 99, i16 99, i16 0>
+; CHECK-NEXT: [[TMP0:%.*]] = or <4 x i16> [[IN:%.*]], <i16 undef, i16 99, i16 undef, i16 undef>
+; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> undef, <4 x i32> <i32 undef, i32 1, i32 1, i32 undef>
; CHECK-NEXT: ret <4 x i16> [[OR]]
;
entry:
OpenPOWER on IntegriCloud