diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -43,15 +43,9 @@ return CFP->isZero() && CFP->isNegative(); // Equivalent for a vector of -0.0's. - if (const ConstantDataVector *CV = dyn_cast(this)) - if (CV->getElementType()->isFloatingPointTy() && CV->isSplat()) - if (CV->getElementAsAPFloat(0).isNegZero()) - return true; - - if (const ConstantVector *CV = dyn_cast(this)) - if (ConstantFP *SplatCFP = dyn_cast_or_null(CV->getSplatValue())) - if (SplatCFP && SplatCFP->isZero() && SplatCFP->isNegative()) - return true; + if (getType()->isVectorTy()) + if (const auto *SplatCFP = dyn_cast_or_null(getSplatValue())) + return SplatCFP->isNegativeZeroValue(); // We've already handled true FP case; any other FP vectors can't represent -0.0. if (getType()->isFPOrFPVectorTy()) @@ -68,16 +62,10 @@ if (const ConstantFP *CFP = dyn_cast(this)) return CFP->isZero(); - // Equivalent for a vector of -0.0's. - if (const ConstantDataVector *CV = dyn_cast(this)) - if (CV->getElementType()->isFloatingPointTy() && CV->isSplat()) - if (CV->getElementAsAPFloat(0).isZero()) - return true; - - if (const ConstantVector *CV = dyn_cast(this)) - if (ConstantFP *SplatCFP = dyn_cast_or_null(CV->getSplatValue())) - if (SplatCFP && SplatCFP->isZero()) - return true; + // Check for constant splat vectors of 1 values. + if (getType()->isVectorTy()) + if (const auto *SplatCFP = dyn_cast_or_null(getSplatValue())) + return SplatCFP->isZero(); // Otherwise, just use +0.0. return isNullValue(); @@ -107,19 +95,10 @@ if (const ConstantFP *CFP = dyn_cast(this)) return CFP->getValueAPF().bitcastToAPInt().isAllOnesValue(); - // Check for constant vectors which are splats of -1 values. - if (const ConstantVector *CV = dyn_cast(this)) - if (Constant *Splat = CV->getSplatValue()) - return Splat->isAllOnesValue(); - - // Check for constant vectors which are splats of -1 values. - if (const ConstantDataVector *CV = dyn_cast(this)) { - if (CV->isSplat()) { - if (CV->getElementType()->isFloatingPointTy()) - return CV->getElementAsAPFloat(0).bitcastToAPInt().isAllOnesValue(); - return CV->getElementAsAPInt(0).isAllOnesValue(); - } - } + // Check for constant splat vectors of 1 values. + if (getType()->isVectorTy()) + if (const auto *SplatVal = getSplatValue()) + return SplatVal->isAllOnesValue(); return false; } @@ -133,19 +112,10 @@ if (const ConstantFP *CFP = dyn_cast(this)) return CFP->getValueAPF().bitcastToAPInt().isOneValue(); - // Check for constant vectors which are splats of 1 values. - if (const ConstantVector *CV = dyn_cast(this)) - if (Constant *Splat = CV->getSplatValue()) - return Splat->isOneValue(); - - // Check for constant vectors which are splats of 1 values. - if (const ConstantDataVector *CV = dyn_cast(this)) { - if (CV->isSplat()) { - if (CV->getElementType()->isFloatingPointTy()) - return CV->getElementAsAPFloat(0).bitcastToAPInt().isOneValue(); - return CV->getElementAsAPInt(0).isOneValue(); - } - } + // Check for constant splat vectors of 1 values. + if (getType()->isVectorTy()) + if (const auto *SplatVal = getSplatValue()) + return SplatVal->isOneValue(); return false; } @@ -160,16 +130,20 @@ return !CFP->getValueAPF().bitcastToAPInt().isOneValue(); // Check that vectors don't contain 1 - if (auto *VTy = dyn_cast(this->getType())) { - unsigned NumElts = cast(VTy)->getNumElements(); - for (unsigned i = 0; i != NumElts; ++i) { - Constant *Elt = this->getAggregateElement(i); + if (auto *VTy = dyn_cast(this->getType())) { + for (unsigned I = 0, E = VTy->getNumElements(); I != E; ++I) { + Constant *Elt = this->getAggregateElement(I); if (!Elt || !Elt->isNotOneValue()) return false; } return true; } + // Check for splats that don't contain 1 + if (getType()->isVectorTy()) + if (const auto *SplatVal = getSplatValue()) + return SplatVal->isNotOneValue(); + // It *may* contain 1, we can't tell. return false; } @@ -183,19 +157,10 @@ if (const ConstantFP *CFP = dyn_cast(this)) return CFP->getValueAPF().bitcastToAPInt().isMinSignedValue(); - // Check for constant vectors which are splats of INT_MIN values. - if (const ConstantVector *CV = dyn_cast(this)) - if (Constant *Splat = CV->getSplatValue()) - return Splat->isMinSignedValue(); - - // Check for constant vectors which are splats of INT_MIN values. - if (const ConstantDataVector *CV = dyn_cast(this)) { - if (CV->isSplat()) { - if (CV->getElementType()->isFloatingPointTy()) - return CV->getElementAsAPFloat(0).bitcastToAPInt().isMinSignedValue(); - return CV->getElementAsAPInt(0).isMinSignedValue(); - } - } + // Check for splats of INT_MIN values. + if (getType()->isVectorTy()) + if (const auto *SplatVal = getSplatValue()) + return SplatVal->isMinSignedValue(); return false; } @@ -210,16 +175,20 @@ return !CFP->getValueAPF().bitcastToAPInt().isMinSignedValue(); // Check that vectors don't contain INT_MIN - if (auto *VTy = dyn_cast(this->getType())) { - unsigned NumElts = cast(VTy)->getNumElements(); - for (unsigned i = 0; i != NumElts; ++i) { - Constant *Elt = this->getAggregateElement(i); + if (auto *VTy = dyn_cast(this->getType())) { + for (unsigned I = 0, E = VTy->getNumElements(); I != E; ++I) { + Constant *Elt = this->getAggregateElement(I); if (!Elt || !Elt->isNotMinSignedValue()) return false; } return true; } + // Check for splats that aren't INT_MIN + if (getType()->isVectorTy()) + if (const auto *SplatVal = getSplatValue()) + return SplatVal->isNotMinSignedValue(); + // It *may* contain INT_MIN, we can't tell. return false; } @@ -227,6 +196,11 @@ bool Constant::isFiniteNonZeroFP() const { if (auto *CFP = dyn_cast(this)) return CFP->getValueAPF().isFiniteNonZero(); + + if (getType()->isVectorTy()) + if (const auto *SplatCFP = dyn_cast_or_null(getSplatValue())) + return SplatCFP->isFiniteNonZeroFP(); + auto *VTy = dyn_cast(getType()); if (!VTy) return false; @@ -241,6 +215,11 @@ bool Constant::isNormalFP() const { if (auto *CFP = dyn_cast(this)) return CFP->getValueAPF().isNormal(); + + if (getType()->isVectorTy()) + if (const auto *SplatCFP = dyn_cast_or_null(getSplatValue())) + return SplatCFP->isNormalFP(); + auto *VTy = dyn_cast(getType()); if (!VTy) return false; @@ -255,6 +234,11 @@ bool Constant::hasExactInverseFP() const { if (auto *CFP = dyn_cast(this)) return CFP->getValueAPF().getExactInverse(nullptr); + + if (getType()->isVectorTy()) + if (const auto *SplatCFP = dyn_cast_or_null(getSplatValue())) + return SplatCFP->hasExactInverseFP(); + auto *VTy = dyn_cast(getType()); if (!VTy) return false; @@ -269,6 +253,11 @@ bool Constant::isNaN() const { if (auto *CFP = dyn_cast(this)) return CFP->isNaN(); + + if (getType()->isVectorTy()) + if (const auto *SplatCFP = dyn_cast_or_null(getSplatValue())) + return SplatCFP->isNaN(); + auto *VTy = dyn_cast(getType()); if (!VTy) return false; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -924,6 +924,12 @@ return ConstantExpr::getNeg(CV); } + // Negate integer vector splats. + if (auto *CV = dyn_cast(V)) + if (CV->getType()->isVectorTy() && + CV->getType()->getScalarType()->isIntegerTy() && CV->getSplatValue()) + return ConstantExpr::getNeg(CV); + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/bitcast.ll b/llvm/test/Transforms/InstCombine/bitcast.ll --- a/llvm/test/Transforms/InstCombine/bitcast.ll +++ b/llvm/test/Transforms/InstCombine/bitcast.ll @@ -465,6 +465,14 @@ ret i32 %out } +define @ScalableAll111( %in) { +; CHECK-LABEL: @ScalableAll111( +; CHECK-NEXT: ret [[IN:%.*]] +; + %out = and %in, bitcast ( shufflevector ( insertelement ( undef, i16 -1, i32 0), undef, zeroinitializer) to ) + ret %out +} + define <2 x i16> @BitcastInsert(i32 %a) { ; CHECK-LABEL: @BitcastInsert( ; CHECK-NEXT: [[R:%.*]] = bitcast i32 [[A:%.*]] to <2 x i16> diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll --- a/llvm/test/Transforms/InstCombine/div.ll +++ b/llvm/test/Transforms/InstCombine/div.ll @@ -1045,3 +1045,45 @@ %d = sdiv <2 x i8> %x, ret <2 x i8> %d } + +define <2 x i8> @sdiv_by_negconst_v2i8(<2 x i8> %x) { +; CHECK-LABEL: @sdiv_by_negconst_v2i8( +; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv <2 x i8> [[X:%.*]], +; CHECK-NEXT: ret <2 x i8> [[DIV_NEG]] +; + %div = sdiv <2 x i8> %x, + %sub = sub <2 x i8> zeroinitializer, %div + ret <2 x i8> %sub +} + +define @sdiv_by_negconst_nxv2i8( %x) { +; CHECK-LABEL: @sdiv_by_negconst_nxv2i8( +; CHECK-NEXT: [[DIV_NEG:%.*]] = sdiv [[X:%.*]], shufflevector ( insertelement ( undef, i8 108, i32 0), undef, zeroinitializer) +; CHECK-NEXT: ret [[DIV_NEG]] +; + %div = sdiv %x, shufflevector ( insertelement ( undef, i8 -108, i32 0), undef, zeroinitializer) + %sub = sub zeroinitializer, %div + ret %sub +} + +define <2 x i8> @sdiv_by_minSigned_v2i8(<2 x i8> %x) { +; CHECK-LABEL: @sdiv_by_minSigned_v2i8( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[DIV_NEG:%.*]] = sext <2 x i1> [[TMP1]] to <2 x i8> +; CHECK-NEXT: ret <2 x i8> [[DIV_NEG]] +; + %div = sdiv <2 x i8> %x, + %sub = sub <2 x i8> zeroinitializer, %div + ret <2 x i8> %sub +} + +define @sdiv_by_minSigned_nxv2i8( %x) { +; CHECK-LABEL: @sdiv_by_minSigned_nxv2i8( +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq [[X:%.*]], shufflevector ( insertelement ( undef, i8 -128, i32 0), undef, zeroinitializer) +; CHECK-NEXT: [[DIV_NEG:%.*]] = sext [[TMP1]] to +; CHECK-NEXT: ret [[DIV_NEG]] +; + %div = sdiv %x, shufflevector ( insertelement ( undef, i8 -128, i32 0), undef, zeroinitializer) + %sub = sub zeroinitializer, %div + ret %sub +} diff --git a/llvm/test/Transforms/InstCombine/fdiv.ll b/llvm/test/Transforms/InstCombine/fdiv.ll --- a/llvm/test/Transforms/InstCombine/fdiv.ll +++ b/llvm/test/Transforms/InstCombine/fdiv.ll @@ -85,6 +85,15 @@ ret <2 x float> %div } +define @exact_inverse_scalable_splat( %x) { +; CHECK-LABEL: @exact_inverse_scalable_splat( +; CHECK-NEXT: [[DIV:%.*]] = fmul [[X:%.*]], shufflevector ( insertelement ( undef, float 2.500000e-01, i32 0), undef, zeroinitializer) +; CHECK-NEXT: ret [[DIV]] +; + %div = fdiv %x, shufflevector ( insertelement ( undef, float 4.0, i32 0), undef, zeroinitializer) + ret %div +} + ; Fast math allows us to replace this fdiv. define <2 x float> @not_exact_but_allow_recip_splat(<2 x float> %x) { diff --git a/llvm/test/Transforms/InstCombine/fmul.ll b/llvm/test/Transforms/InstCombine/fmul.ll --- a/llvm/test/Transforms/InstCombine/fmul.ll +++ b/llvm/test/Transforms/InstCombine/fmul.ll @@ -781,6 +781,30 @@ ret float %t3 } +define <2 x float> @fmul_fadd_distribute_vec(<2 x float> %x) { +; CHECK-LABEL: @fmul_fadd_distribute_vec( +; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc <2 x float> [[X:%.*]], +; CHECK-NEXT: [[T3:%.*]] = fadd reassoc <2 x float> [[TMP1]], +; CHECK-NEXT: ret <2 x float> [[T3]] +; + %t1 = fadd <2 x float> , %x + %t3 = fmul reassoc <2 x float> %t1, + ret <2 x float> %t3 +} + +define @fmul_fadd_distribute_scalablevec( %x) { +; CHECK-LABEL: @fmul_fadd_distribute_scalablevec( +; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc [[X:%.*]], shufflevector ( insertelement ( undef, float 6.000000e+03, i32 0), undef, zeroinitializer) +; CHECK-NEXT: [[T3:%.*]] = fadd reassoc [[TMP1]], shufflevector ( insertelement ( undef, float 1.200000e+07, i32 0), undef, zeroinitializer) +; CHECK-NEXT: ret [[T3]] +; + %t1 = fadd shufflevector ( insertelement ( undef, float 2.0e+3, i32 0), undef, zeroinitializer), %x + %t3 = fmul reassoc %t1, shufflevector ( insertelement ( undef, float 6.0e+3, i32 0), undef, zeroinitializer) + + + ret %t3 +} + ; (X - C1) * C2 --> (X * C2) - C1*C2 define float @fmul_fsub_distribute1(float %x) { @@ -1169,6 +1193,7 @@ define @mul_scalable_splat_zero( %z) { ; CHECK-LABEL: @mul_scalable_splat_zero( ; CHECK-NEXT: ret zeroinitializer +; %shuf = shufflevector insertelement ( undef, float 0.0, i32 0), undef, zeroinitializer %t3 = fmul fast %shuf, %z ret %t3 diff --git a/llvm/test/Transforms/InstCombine/icmp-vec.ll b/llvm/test/Transforms/InstCombine/icmp-vec.ll --- a/llvm/test/Transforms/InstCombine/icmp-vec.ll +++ b/llvm/test/Transforms/InstCombine/icmp-vec.ll @@ -373,3 +373,29 @@ %cmp = icmp sgt <4 x i8> %splatx, ret <4 x i1> %cmp } + +; Check that we don't absorb the compare into the select, which is in the +; canonical form of logical or. +define <2 x i1> @icmp_logical_or_vec(<2 x i64> %x, <2 x i64> %y, <2 x i1> %falseval) { +; CHECK-LABEL: @icmp_logical_or_vec( +; CHECK-NEXT: [[CMP_NE:%.*]] = icmp ne <2 x i64> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP_NE]], <2 x i1> , <2 x i1> [[FALSEVAL:%.*]] +; CHECK-NEXT: ret <2 x i1> [[SEL]] +; + %cmp.ne = icmp ne <2 x i64> %x, zeroinitializer + %sel = select <2 x i1> %cmp.ne, <2 x i1> shufflevector (<2 x i1> insertelement (<2 x i1> undef, i1 true, i32 0), <2 x i1> undef, <2 x i32> zeroinitializer), <2 x i1> %falseval + ret <2 x i1> %sel +} + +; The above, but for scalable vectors. Absorbing the compare into the select +; and breaking the canonical form led to an infinite loop. +define @icmp_logical_or_scalablevec( %x, %y, %falseval) { +; CHECK-LABEL: @icmp_logical_or_scalablevec( +; CHECK-NEXT: [[CMP_NE:%.*]] = icmp ne [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[SEL:%.*]] = select [[CMP_NE]], shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer), [[FALSEVAL:%.*]] +; CHECK-NEXT: ret [[SEL]] +; + %cmp.ne = icmp ne %x, zeroinitializer + %sel = select %cmp.ne, shufflevector ( insertelement ( undef, i1 true, i32 0), undef, zeroinitializer), %falseval + ret %sel +} diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/llvm/test/Transforms/InstCombine/sub.ll @@ -830,6 +830,42 @@ ret i32 %sub } +define <2 x i32> @test44vec(<2 x i32> %x) { +; CHECK-LABEL: @test44vec( +; CHECK-NEXT: [[SUB:%.*]] = add nsw <2 x i32> [[X:%.*]], +; CHECK-NEXT: ret <2 x i32> [[SUB]] +; + %sub = sub nsw <2 x i32> %x, + ret <2 x i32> %sub +} + +define @test44scalablevec( %x) { +; CHECK-LABEL: @test44scalablevec( +; CHECK-NEXT: [[SUB:%.*]] = add nsw [[X:%.*]], shufflevector ( insertelement ( undef, i32 -32768, i32 0), undef, zeroinitializer) +; CHECK-NEXT: ret [[SUB]] +; + %sub = sub nsw %x, shufflevector ( insertelement ( undef, i32 32768, i32 0), undef, zeroinitializer) + ret %sub +} + +define <2 x i16> @test44vecminval(<2 x i16> %x) { +; CHECK-LABEL: @test44vecminval( +; CHECK-NEXT: [[SUB:%.*]] = xor <2 x i16> [[X:%.*]], +; CHECK-NEXT: ret <2 x i16> [[SUB]] +; + %sub = sub nsw <2 x i16> %x, + ret <2 x i16> %sub +} + +define @test44scalablevecminval( %x) { +; CHECK-LABEL: @test44scalablevecminval( +; CHECK-NEXT: [[SUB:%.*]] = add [[X:%.*]], shufflevector ( insertelement ( undef, i16 -32768, i32 0), undef, zeroinitializer) +; CHECK-NEXT: ret [[SUB]] +; + %sub = sub nsw %x, shufflevector ( insertelement ( undef, i16 -32768, i32 0), undef, zeroinitializer) + ret %sub +} + define i32 @test45(i32 %x, i32 %y) { ; CHECK-LABEL: @test45( ; CHECK-NEXT: [[SUB:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]