diff options
| -rw-r--r-- | llvm/include/llvm/IR/Constants.h | 5 | ||||
| -rw-r--r-- | llvm/lib/IR/Constants.cpp | 11 | ||||
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 20 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/fdiv.ll | 17 |
4 files changed, 39 insertions, 14 deletions
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h index 0094fd54992..0ec082c23eb 100644 --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -283,6 +283,11 @@ public: /// for simple constant values like 2.0/1.0 etc, that are known-valid both as /// host double and as the target format. static Constant *get(Type* Ty, double V); + + /// If Ty is a vector type, return a Constant with a splat of the given + /// value. Otherwise return a ConstantFP for the given value. + static Constant *get(Type *Ty, const APFloat &V); + static Constant *get(Type* Ty, StringRef Str); static ConstantFP *get(LLVMContext &Context, const APFloat &V); static Constant *getNaN(Type *Ty, bool Negative = false, unsigned type = 0); diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index dccba779deb..a601f54a359 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -635,6 +635,17 @@ Constant *ConstantFP::get(Type *Ty, double V) { return C; } +Constant *ConstantFP::get(Type *Ty, const APFloat &V) { + ConstantFP *C = get(Ty->getContext(), V); + assert(C->getType() == Ty->getScalarType() && + "ConstantFP type doesn't match the type implied by its value!"); + + // For vectors, broadcast the value. + if (auto *VTy = dyn_cast<VectorType>(Ty)) + return ConstantVector::getSplat(VTy->getNumElements(), C); + + return C; +} Constant *ConstantFP::get(Type *Ty, StringRef Str) { LLVMContext &Context = Ty->getContext(); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 5457f19d7f4..57a30558a98 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1319,21 +1319,19 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { /// Try to convert X/C into X * (1/C). static Instruction *foldFDivConstantDivisor(BinaryOperator &FDiv) { - // TODO: Handle vector constants. - ConstantFP *CFP; - if (!match(FDiv.getOperand(1), m_ConstantFP(CFP))) + // TODO: Handle non-splat vector constants. + const APFloat *C; + if (!match(FDiv.getOperand(1), m_APFloat(C))) return nullptr; - const APFloat &FpVal = CFP->getValueAPF(); - APFloat Reciprocal(FpVal.getSemantics()); - // This returns false if the inverse would be a denormal. - bool HasRecip = FpVal.getExactInverse(&Reciprocal); + APFloat Reciprocal(C->getSemantics()); + bool HasRecip = C->getExactInverse(&Reciprocal); // If the inverse is not exact, we may still be able to convert if we are // not operating with strict math. - if (!HasRecip && FDiv.hasAllowReciprocal() && FpVal.isFiniteNonZero()) { - Reciprocal = APFloat(FpVal.getSemantics(), 1.0f); - Reciprocal.divide(FpVal, APFloat::rmNearestTiesToEven); + if (!HasRecip && FDiv.hasAllowReciprocal() && C->isFiniteNonZero()) { + Reciprocal = APFloat(C->getSemantics(), 1.0f); + Reciprocal.divide(*C, APFloat::rmNearestTiesToEven); // Disallow denormal constants because we don't know what would happen // on all targets. // TODO: Function attributes can tell us that denorms are flushed? @@ -1343,7 +1341,7 @@ static Instruction *foldFDivConstantDivisor(BinaryOperator &FDiv) { if (!HasRecip) return nullptr; - auto *RecipCFP = ConstantFP::get(FDiv.getContext(), Reciprocal); + auto *RecipCFP = ConstantFP::get(FDiv.getType(), Reciprocal); return BinaryOperator::CreateFMul(FDiv.getOperand(0), RecipCFP); } diff --git a/llvm/test/Transforms/InstCombine/fdiv.ll b/llvm/test/Transforms/InstCombine/fdiv.ll index ac9733b11c4..03e0a36b0f8 100644 --- a/llvm/test/Transforms/InstCombine/fdiv.ll +++ b/llvm/test/Transforms/InstCombine/fdiv.ll @@ -66,17 +66,28 @@ define float @not_exact_but_allow_recip_but_denorm(float %x) { ret float %div } -; FIXME: Vector neglect. - define <2 x float> @exact_inverse_splat(<2 x float> %x) { ; CHECK-LABEL: @exact_inverse_splat( -; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.000000e+00, float 4.000000e+00> +; CHECK-NEXT: [[DIV:%.*]] = fmul <2 x float> [[X:%.*]], <float 2.500000e-01, float 2.500000e-01> ; CHECK-NEXT: ret <2 x float> [[DIV]] ; %div = fdiv <2 x float> %x, <float 4.0, float 4.0> ret <2 x float> %div } +; Fast math allows us to replace this fdiv. + +define <2 x float> @not_exact_but_allow_recip_splat(<2 x float> %x) { +; CHECK-LABEL: @not_exact_but_allow_recip_splat( +; CHECK-NEXT: [[DIV:%.*]] = fmul arcp <2 x float> [[X:%.*]], <float 0x3FD5555560000000, float 0x3FD5555560000000> +; CHECK-NEXT: ret <2 x float> [[DIV]] +; + %div = fdiv arcp <2 x float> %x, <float 3.0, float 3.0> + ret <2 x float> %div +} + +; FIXME: Vector neglect. + define <2 x float> @exact_inverse_vec(<2 x float> %x) { ; CHECK-LABEL: @exact_inverse_vec( ; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.000000e+00, float 8.000000e+00> |

