mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
Enable double to float shrinking optimizations for binary functions like 'fmin/fmax'. Fix radar:15283121
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197434 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
89452cf827
commit
4faf2ba0c7
@ -251,6 +251,18 @@ namespace llvm {
|
|||||||
floorf,
|
floorf,
|
||||||
/// long double floorl(long double x);
|
/// long double floorl(long double x);
|
||||||
floorl,
|
floorl,
|
||||||
|
/// double fmax(double x, double y);
|
||||||
|
fmax,
|
||||||
|
/// float fmaxf(float x, float y);
|
||||||
|
fmaxf,
|
||||||
|
/// long double fmaxl(long double x, long double y);
|
||||||
|
fmaxl,
|
||||||
|
/// double fmin(double x, double y);
|
||||||
|
fmin,
|
||||||
|
/// float fminf(float x, float y);
|
||||||
|
fminf,
|
||||||
|
/// long double fminl(long double x, long double y);
|
||||||
|
fminl,
|
||||||
/// double fmod(double x, double y);
|
/// double fmod(double x, double y);
|
||||||
fmod,
|
fmod,
|
||||||
/// float fmodf(float x, float y);
|
/// float fmodf(float x, float y);
|
||||||
@ -703,6 +715,8 @@ public:
|
|||||||
case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl:
|
case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl:
|
||||||
case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite:
|
case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite:
|
||||||
case LibFunc::sqrtl_finite:
|
case LibFunc::sqrtl_finite:
|
||||||
|
case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl:
|
||||||
|
case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl:
|
||||||
case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl:
|
case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl:
|
||||||
case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl:
|
case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl:
|
||||||
case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill:
|
case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill:
|
||||||
|
@ -83,6 +83,14 @@ namespace llvm {
|
|||||||
Value *EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
|
Value *EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
|
||||||
const AttributeSet &Attrs);
|
const AttributeSet &Attrs);
|
||||||
|
|
||||||
|
/// EmitUnaryFloatFnCall - Emit a call to the binary function named 'Name'
|
||||||
|
/// (e.g. 'fmin'). This function is known to take type matching 'Op1' and
|
||||||
|
/// 'Op2' and return one value with the same type. If 'Op1/Op2' are long
|
||||||
|
/// double, 'l' is added as the suffix of name, if 'Op1/Op2' are float, we
|
||||||
|
/// add a 'f' suffix.
|
||||||
|
Value *EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name,
|
||||||
|
IRBuilder<> &B, const AttributeSet &Attrs);
|
||||||
|
|
||||||
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
|
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
|
||||||
/// is an integer.
|
/// is an integer.
|
||||||
Value *EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD,
|
Value *EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD,
|
||||||
|
@ -140,6 +140,12 @@ const char* TargetLibraryInfo::StandardNames[LibFunc::NumLibFuncs] =
|
|||||||
"floor",
|
"floor",
|
||||||
"floorf",
|
"floorf",
|
||||||
"floorl",
|
"floorl",
|
||||||
|
"fmax",
|
||||||
|
"fmaxf",
|
||||||
|
"fmaxl",
|
||||||
|
"fmin",
|
||||||
|
"fminf",
|
||||||
|
"fminl",
|
||||||
"fmod",
|
"fmod",
|
||||||
"fmodf",
|
"fmodf",
|
||||||
"fmodl",
|
"fmodl",
|
||||||
@ -453,6 +459,8 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T,
|
|||||||
TLI.setUnavailable(LibFunc::fabsf); // Win32 and Win64 both lack fabsf
|
TLI.setUnavailable(LibFunc::fabsf); // Win32 and Win64 both lack fabsf
|
||||||
TLI.setUnavailable(LibFunc::fabsl);
|
TLI.setUnavailable(LibFunc::fabsl);
|
||||||
TLI.setUnavailable(LibFunc::floorl);
|
TLI.setUnavailable(LibFunc::floorl);
|
||||||
|
TLI.setUnavailable(LibFunc::fmaxl);
|
||||||
|
TLI.setUnavailable(LibFunc::fminl);
|
||||||
TLI.setUnavailable(LibFunc::fmodl);
|
TLI.setUnavailable(LibFunc::fmodl);
|
||||||
TLI.setUnavailable(LibFunc::frexpl);
|
TLI.setUnavailable(LibFunc::frexpl);
|
||||||
TLI.setUnavailable(LibFunc::logl);
|
TLI.setUnavailable(LibFunc::logl);
|
||||||
@ -523,6 +531,8 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T,
|
|||||||
TLI.setUnavailable(LibFunc::coshf);
|
TLI.setUnavailable(LibFunc::coshf);
|
||||||
TLI.setUnavailable(LibFunc::expf);
|
TLI.setUnavailable(LibFunc::expf);
|
||||||
TLI.setUnavailable(LibFunc::floorf);
|
TLI.setUnavailable(LibFunc::floorf);
|
||||||
|
TLI.setUnavailable(LibFunc::fminf);
|
||||||
|
TLI.setUnavailable(LibFunc::fmaxf);
|
||||||
TLI.setUnavailable(LibFunc::fmodf);
|
TLI.setUnavailable(LibFunc::fmodf);
|
||||||
TLI.setUnavailable(LibFunc::logf);
|
TLI.setUnavailable(LibFunc::logf);
|
||||||
TLI.setUnavailable(LibFunc::powf);
|
TLI.setUnavailable(LibFunc::powf);
|
||||||
|
@ -286,6 +286,21 @@ Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2,
|
|||||||
return CI;
|
return CI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append a suffix to the function name according to the type of 'Op'.
|
||||||
|
static void AppendTypeSuffix(Value *Op, StringRef &Name, SmallString<20> &NameBuffer) {
|
||||||
|
if (!Op->getType()->isDoubleTy()) {
|
||||||
|
NameBuffer += Name;
|
||||||
|
|
||||||
|
if (Op->getType()->isFloatTy())
|
||||||
|
NameBuffer += 'f';
|
||||||
|
else
|
||||||
|
NameBuffer += 'l';
|
||||||
|
|
||||||
|
Name = NameBuffer;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g.
|
/// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g.
|
||||||
/// 'floor'). This function is known to take a single of type matching 'Op' and
|
/// 'floor'). This function is known to take a single of type matching 'Op' and
|
||||||
/// returns one value with the same type. If 'Op' is a long double, 'l' is
|
/// returns one value with the same type. If 'Op' is a long double, 'l' is
|
||||||
@ -293,15 +308,7 @@ Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2,
|
|||||||
Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
|
Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
|
||||||
const AttributeSet &Attrs) {
|
const AttributeSet &Attrs) {
|
||||||
SmallString<20> NameBuffer;
|
SmallString<20> NameBuffer;
|
||||||
if (!Op->getType()->isDoubleTy()) {
|
AppendTypeSuffix(Op, Name, NameBuffer);
|
||||||
// If we need to add a suffix, copy into NameBuffer.
|
|
||||||
NameBuffer += Name;
|
|
||||||
if (Op->getType()->isFloatTy())
|
|
||||||
NameBuffer += 'f'; // floorf
|
|
||||||
else
|
|
||||||
NameBuffer += 'l'; // floorl
|
|
||||||
Name = NameBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
||||||
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
|
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
|
||||||
@ -314,6 +321,27 @@ Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
|
|||||||
return CI;
|
return CI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EmitBinaryFloatFnCall - Emit a call to the binary function named 'Name'
|
||||||
|
/// (e.g. 'fmin'). This function is known to take type matching 'Op1' and 'Op2'
|
||||||
|
/// and return one value with the same type. If 'Op1/Op2' are long double, 'l'
|
||||||
|
/// is added as the suffix of name, if 'Op1/Op2' is a float, we add a 'f'
|
||||||
|
/// suffix.
|
||||||
|
Value *llvm::EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name,
|
||||||
|
IRBuilder<> &B, const AttributeSet &Attrs) {
|
||||||
|
SmallString<20> NameBuffer;
|
||||||
|
AppendTypeSuffix(Op1, Name, NameBuffer);
|
||||||
|
|
||||||
|
Module *M = B.GetInsertBlock()->getParent()->getParent();
|
||||||
|
Value *Callee = M->getOrInsertFunction(Name, Op1->getType(),
|
||||||
|
Op1->getType(), Op2->getType(), NULL);
|
||||||
|
CallInst *CI = B.CreateCall2(Callee, Op1, Op2, Name);
|
||||||
|
CI->setAttributes(Attrs);
|
||||||
|
if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
|
||||||
|
CI->setCallingConv(F->getCallingConv());
|
||||||
|
|
||||||
|
return CI;
|
||||||
|
}
|
||||||
|
|
||||||
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
|
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
|
||||||
/// is an integer.
|
/// is an integer.
|
||||||
Value *llvm::EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD,
|
Value *llvm::EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD,
|
||||||
|
@ -1100,6 +1100,49 @@ struct UnaryDoubleFPOpt : public LibCallOptimization {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Double -> Float Shrinking Optimizations for Binary Functions like 'fmin/fmax'
|
||||||
|
struct BinaryDoubleFPOpt : public LibCallOptimization {
|
||||||
|
bool CheckRetType;
|
||||||
|
BinaryDoubleFPOpt(bool CheckReturnType): CheckRetType(CheckReturnType) {}
|
||||||
|
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||||
|
FunctionType *FT = Callee->getFunctionType();
|
||||||
|
// Just make sure this has 2 arguments of the same FP type, which match the
|
||||||
|
// result type.
|
||||||
|
if (FT->getNumParams() != 2 || FT->getReturnType() != FT->getParamType(0) ||
|
||||||
|
FT->getParamType(0) != FT->getParamType(1) ||
|
||||||
|
!FT->getParamType(0)->isFloatingPointTy())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (CheckRetType) {
|
||||||
|
// Check if all the uses for function like 'fmin/fmax' are converted to
|
||||||
|
// float.
|
||||||
|
for (Value::use_iterator UseI = CI->use_begin(); UseI != CI->use_end();
|
||||||
|
++UseI) {
|
||||||
|
FPTruncInst *Cast = dyn_cast<FPTruncInst>(*UseI);
|
||||||
|
if (Cast == 0 || !Cast->getType()->isFloatTy())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 == 0 || !Cast1->getOperand(0)->getType()->isFloatTy() ||
|
||||||
|
Cast2 == 0 || !Cast2->getOperand(0)->getType()->isFloatTy())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// fmin((double)floatval1, (double)floatval2)
|
||||||
|
// -> (double)fmin(floatval1, floatval2)
|
||||||
|
Value *V = NULL;
|
||||||
|
Value *V1 = Cast1->getOperand(0);
|
||||||
|
Value *V2 = Cast2->getOperand(0);
|
||||||
|
V = EmitBinaryFloatFnCall(V1, V2, Callee->getName(), B,
|
||||||
|
Callee->getAttributes());
|
||||||
|
return B.CreateFPExt(V, B.getDoubleTy());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct UnsafeFPLibCallOptimization : public LibCallOptimization {
|
struct UnsafeFPLibCallOptimization : public LibCallOptimization {
|
||||||
bool UnsafeFPShrink;
|
bool UnsafeFPShrink;
|
||||||
UnsafeFPLibCallOptimization(bool UnsafeFPShrink) {
|
UnsafeFPLibCallOptimization(bool UnsafeFPShrink) {
|
||||||
@ -1981,6 +2024,7 @@ static MemSetOpt MemSet;
|
|||||||
|
|
||||||
// Math library call optimizations.
|
// Math library call optimizations.
|
||||||
static UnaryDoubleFPOpt UnaryDoubleFP(false);
|
static UnaryDoubleFPOpt UnaryDoubleFP(false);
|
||||||
|
static BinaryDoubleFPOpt BinaryDoubleFP(false);
|
||||||
static UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true);
|
static UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true);
|
||||||
static SinCosPiOpt SinCosPi;
|
static SinCosPiOpt SinCosPi;
|
||||||
|
|
||||||
@ -2150,6 +2194,11 @@ LibCallOptimization *LibCallSimplifierImpl::lookupOptimization(CallInst *CI) {
|
|||||||
if (UnsafeFPShrink && hasFloatVersion(FuncName))
|
if (UnsafeFPShrink && hasFloatVersion(FuncName))
|
||||||
return &UnsafeUnaryDoubleFP;
|
return &UnsafeUnaryDoubleFP;
|
||||||
return 0;
|
return 0;
|
||||||
|
case LibFunc::fmin:
|
||||||
|
case LibFunc::fmax:
|
||||||
|
if (hasFloatVersion(FuncName))
|
||||||
|
return &BinaryDoubleFP;
|
||||||
|
return 0;
|
||||||
case LibFunc::memcpy_chk:
|
case LibFunc::memcpy_chk:
|
||||||
return &MemCpyChk;
|
return &MemCpyChk;
|
||||||
default:
|
default:
|
||||||
|
@ -170,6 +170,58 @@ define i32 @test14(float %x, float %y) nounwind uwtable {
|
|||||||
; CHECK-NEXT: fcmp oeq float %truncf, %y
|
; CHECK-NEXT: fcmp oeq float %truncf, %y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define i32 @test15(float %x, float %y, float %z) nounwind uwtable {
|
||||||
|
%1 = fpext float %x to double
|
||||||
|
%2 = fpext float %y to double
|
||||||
|
%3 = call double @fmin(double %1, double %2) nounwind
|
||||||
|
%4 = fpext float %z to double
|
||||||
|
%5 = fcmp oeq double %3, %4
|
||||||
|
%6 = zext i1 %5 to i32
|
||||||
|
ret i32 %6
|
||||||
|
; CHECK-LABEL: @test15(
|
||||||
|
; CHECK-NEXT: %fminf = call float @fminf(float %x, float %y)
|
||||||
|
; CHECK-NEXT: fcmp oeq float %fminf, %z
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test16(float %x, float %y, float %z) nounwind uwtable {
|
||||||
|
%1 = fpext float %z to double
|
||||||
|
%2 = fpext float %x to double
|
||||||
|
%3 = fpext float %y to double
|
||||||
|
%4 = call double @fmin(double %2, double %3) nounwind
|
||||||
|
%5 = fcmp oeq double %1, %4
|
||||||
|
%6 = zext i1 %5 to i32
|
||||||
|
ret i32 %6
|
||||||
|
; CHECK-LABEL: @test16(
|
||||||
|
; CHECK-NEXT: %fminf = call float @fminf(float %x, float %y)
|
||||||
|
; CHECK-NEXT: fcmp oeq float %fminf, %z
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test17(float %x, float %y, float %z) nounwind uwtable {
|
||||||
|
%1 = fpext float %x to double
|
||||||
|
%2 = fpext float %y to double
|
||||||
|
%3 = call double @fmax(double %1, double %2) nounwind
|
||||||
|
%4 = fpext float %z to double
|
||||||
|
%5 = fcmp oeq double %3, %4
|
||||||
|
%6 = zext i1 %5 to i32
|
||||||
|
ret i32 %6
|
||||||
|
; CHECK-LABEL: @test17(
|
||||||
|
; CHECK-NEXT: %fmaxf = call float @fmaxf(float %x, float %y)
|
||||||
|
; CHECK-NEXT: fcmp oeq float %fmaxf, %z
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test18(float %x, float %y, float %z) nounwind uwtable {
|
||||||
|
%1 = fpext float %z to double
|
||||||
|
%2 = fpext float %x to double
|
||||||
|
%3 = fpext float %y to double
|
||||||
|
%4 = call double @fmax(double %2, double %3) nounwind
|
||||||
|
%5 = fcmp oeq double %1, %4
|
||||||
|
%6 = zext i1 %5 to i32
|
||||||
|
ret i32 %6
|
||||||
|
; CHECK-LABEL: @test18(
|
||||||
|
; CHECK-NEXT: %fmaxf = call float @fmaxf(float %x, float %y)
|
||||||
|
; CHECK-NEXT: fcmp oeq float %fmaxf, %z
|
||||||
|
}
|
||||||
|
|
||||||
declare double @fabs(double) nounwind readnone
|
declare double @fabs(double) nounwind readnone
|
||||||
declare double @ceil(double) nounwind readnone
|
declare double @ceil(double) nounwind readnone
|
||||||
declare double @floor(double) nounwind readnone
|
declare double @floor(double) nounwind readnone
|
||||||
@ -177,3 +229,5 @@ declare double @nearbyint(double) nounwind readnone
|
|||||||
declare double @rint(double) nounwind readnone
|
declare double @rint(double) nounwind readnone
|
||||||
declare double @round(double) nounwind readnone
|
declare double @round(double) nounwind readnone
|
||||||
declare double @trunc(double) nounwind readnone
|
declare double @trunc(double) nounwind readnone
|
||||||
|
declare double @fmin(double, double) nounwind readnone
|
||||||
|
declare double @fmax(double, double) nounwind readnone
|
||||||
|
Loading…
Reference in New Issue
Block a user