// Math Library Optimizations
//===----------------------------------------------------------------------===//
+/// Return a variant of Val with float type.
+/// Currently this works in two cases: If Val is an FPExtension of a float
+/// value to something bigger, simply return the operand.
+/// If Val is a ConstantFP but can be converted to a float ConstantFP without
+/// loss of precision do so.
+static Value *valueHasFloatPrecision(Value *Val) {
+ if (FPExtInst *Cast = dyn_cast<FPExtInst>(Val)) {
+ Value *Op = Cast->getOperand(0);
+ if (Op->getType()->isFloatTy())
+ return Op;
+ }
+ if (ConstantFP *Const = dyn_cast<ConstantFP>(Val)) {
+ APFloat F = Const->getValueAPF();
+ bool loosesInfo;
+ (void)F.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven,
+ &loosesInfo);
+ if (!loosesInfo)
+ return ConstantFP::get(Const->getContext(), F);
+ }
+ return nullptr;
+}
+
//===----------------------------------------------------------------------===//
// Double -> Float Shrinking Optimizations for Unary Functions like 'floor'
}
// If this is something like 'floor((double)floatval)', convert to floorf.
- FPExtInst *Cast = dyn_cast<FPExtInst>(CI->getArgOperand(0));
- if (!Cast || !Cast->getOperand(0)->getType()->isFloatTy())
+ Value *V = valueHasFloatPrecision(CI->getArgOperand(0));
+ if (V == nullptr)
return nullptr;
// floor((double)floatval) -> (double)floorf(floatval)
- Value *V = Cast->getOperand(0);
if (Callee->isIntrinsic()) {
Module *M = CI->getParent()->getParent()->getParent();
Intrinsic::ID IID = (Intrinsic::ID) Callee->getIntrinsicID();
return nullptr;
// If this is something like 'fmin((double)floatval1, (double)floatval2)',
- // we convert it to fminf.
- FPExtInst *Cast1 = dyn_cast<FPExtInst>(CI->getArgOperand(0));
- FPExtInst *Cast2 = dyn_cast<FPExtInst>(CI->getArgOperand(1));
- if (!Cast1 || !Cast1->getOperand(0)->getType()->isFloatTy() || !Cast2 ||
- !Cast2->getOperand(0)->getType()->isFloatTy())
+ // or fmin(1.0, (double)floatval), then we convert it to fminf.
+ Value *V1 = valueHasFloatPrecision(CI->getArgOperand(0));
+ if (V1 == nullptr)
+ return nullptr;
+ Value *V2 = valueHasFloatPrecision(CI->getArgOperand(1));
+ if (V2 == nullptr)
return nullptr;
// fmin((double)floatval1, (double)floatval2)
- // -> (double)fmin(floatval1, floatval2)
- Value *V = nullptr;
- Value *V1 = Cast1->getOperand(0);
- Value *V2 = Cast2->getOperand(0);
+ // -> (double)fminf(floatval1, floatval2)
// TODO: Handle intrinsics in the same way as in optimizeUnaryDoubleFP().
- V = EmitBinaryFloatFnCall(V1, V2, Callee->getName(), B,
- Callee->getAttributes());
+ Value *V = EmitBinaryFloatFnCall(V1, V2, Callee->getName(), B,
+ Callee->getAttributes());
return B.CreateFPExt(V, B.getDoubleTy());
}
; CHECK-NEXT: fcmp oeq float %copysignf, %z
}
+define i32 @test20(float %x, float %y) nounwind uwtable {
+ %1 = fpext float %y to double
+ %2 = fpext float %x to double
+ %3 = call double @fmin(double 1.000000e+00, double %2) nounwind
+ %4 = fcmp oeq double %1, %3
+ %5 = zext i1 %4 to i32
+ ret i32 %5
+; CHECK-LABEL: @test20(
+; CHECK-NEXT: %fminf = call float @fminf(float 1.000000e+00, float %x)
+; CHECK-NEXT: fcmp oeq float %fminf, %y
+}
+
+define i32 @test21(float %x, float %y) nounwind uwtable {
+ %1 = fpext float %y to double
+ %2 = fpext float %x to double
+ %3 = call double @fmin(double 1.300000e+00, double %2) nounwind
+ %4 = fcmp oeq double %1, %3
+ %5 = zext i1 %4 to i32
+ ret i32 %5
+; should not be changed to fminf as the constant would loose precision
+; CHECK-LABEL: @test21(
+; CHECK: %3 = call double @fmin(double 1.300000e+00, double %2)
+}
+
declare double @fabs(double) nounwind readnone
declare double @ceil(double) nounwind readnone
declare double @copysign(double, double) nounwind readnone