diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index a6cd8331008835..f6dbe9b5ea9376 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(C1) || isa(C2)); diff --git a/llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll b/llvm/test/Analysis/ConstantFolding/binop-identity-undef.ll index 7bb824dfb465cf..68307892187c4f 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 07c888ac6ae075..b7b02a597d21c3 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> -; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], -; CHECK-NEXT: ret <4 x i16> [[AND]] +; CHECK-NEXT: ret <4 x i16> ; entry: %shuffle = shufflevector <4 x i16> %add, <4 x i16> undef, <4 x i32> @@ -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> -; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[SHUFFLE]], +; CHECK-NEXT: [[TMP0:%.*]] = and <4 x i16> [[ADD:%.*]], +; CHECK-NEXT: [[AND:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> undef, <4 x i32> ; 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> -; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], -; CHECK-NEXT: ret <4 x i16> [[OR]] +; CHECK-NEXT: ret <4 x i16> ; entry: %shuffle = shufflevector <4 x i16> %in, <4 x i16> undef, <4 x i32> @@ -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> -; CHECK-NEXT: [[OR:%.*]] = or <4 x i16> [[SHUFFLE]], +; CHECK-NEXT: [[TMP0:%.*]] = or <4 x i16> [[IN:%.*]], +; CHECK-NEXT: [[OR:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> undef, <4 x i32> ; CHECK-NEXT: ret <4 x i16> [[OR]] ; entry: