From: Chris Lattner Date: Sun, 27 Jan 2008 05:29:54 +0000 (+0000) Subject: Fold fptrunc(add (fpextend x), (fpextend y)) -> add(x,y), as GCC does. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b753065f6d415ee4a63a045a4150caaebd5d05a2;p=oota-llvm.git Fold fptrunc(add (fpextend x), (fpextend y)) -> add(x,y), as GCC does. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@46406 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index d17035c161e..49f1c45f395 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -203,7 +203,7 @@ namespace { Instruction *visitTrunc(TruncInst &CI); Instruction *visitZExt(ZExtInst &CI); Instruction *visitSExt(SExtInst &CI); - Instruction *visitFPTrunc(CastInst &CI); + Instruction *visitFPTrunc(FPTruncInst &CI); Instruction *visitFPExt(CastInst &CI); Instruction *visitFPToUI(CastInst &CI); Instruction *visitFPToSI(CastInst &CI); @@ -7141,8 +7141,80 @@ Instruction *InstCombiner::visitSExt(SExtInst &CI) { return 0; } -Instruction *InstCombiner::visitFPTrunc(CastInst &CI) { - return commonCastTransforms(CI); +/// FitsInFPType - Return a Constant* for the specified FP constant if it fits +/// in the specified FP type without changing its value. +static Constant *FitsInFPType(ConstantFP *CFP, const Type *FPTy, + const fltSemantics &Sem) { + APFloat F = CFP->getValueAPF(); + if (F.convert(Sem, APFloat::rmNearestTiesToEven) == APFloat::opOK) + return ConstantFP::get(FPTy, F); + return 0; +} + +/// LookThroughFPExtensions - If this is an fp extension instruction, look +/// through it until we get the source value. +static Value *LookThroughFPExtensions(Value *V) { + if (Instruction *I = dyn_cast(V)) + if (I->getOpcode() == Instruction::FPExt) + return LookThroughFPExtensions(I->getOperand(0)); + + // If this value is a constant, return the constant in the smallest FP type + // that can accurately represent it. This allows us to turn + // (float)((double)X+2.0) into x+2.0f. + if (ConstantFP *CFP = dyn_cast(V)) { + if (CFP->getType() == Type::PPC_FP128Ty) + return V; // No constant folding of this. + // See if the value can be truncated to float and then reextended. + if (Value *V = FitsInFPType(CFP, Type::FloatTy, APFloat::IEEEsingle)) + return V; + if (CFP->getType() == Type::DoubleTy) + return V; // Won't shrink. + if (Value *V = FitsInFPType(CFP, Type::DoubleTy, APFloat::IEEEdouble)) + return V; + // Don't try to shrink to various long double types. + } + + return V; +} + +Instruction *InstCombiner::visitFPTrunc(FPTruncInst &CI) { + if (Instruction *I = commonCastTransforms(CI)) + return I; + + // If we have fptrunc(add (fpextend x), (fpextend y)), where x and y are + // smaller than the destination type, we can eliminate the truncate by doing + // the add as the smaller type. This applies to add/sub/mul/div as well as + // many builtins (sqrt, etc). + BinaryOperator *OpI = dyn_cast(CI.getOperand(0)); + if (OpI && OpI->hasOneUse()) { + switch (OpI->getOpcode()) { + default: break; + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::FDiv: + case Instruction::FRem: + const Type *SrcTy = OpI->getType(); + Value *LHSTrunc = LookThroughFPExtensions(OpI->getOperand(0)); + Value *RHSTrunc = LookThroughFPExtensions(OpI->getOperand(1)); + if (LHSTrunc->getType() != SrcTy && + RHSTrunc->getType() != SrcTy) { + unsigned DstSize = CI.getType()->getPrimitiveSizeInBits(); + // If the source types were both smaller than the destination type of + // the cast, do this xform. + if (LHSTrunc->getType()->getPrimitiveSizeInBits() <= DstSize && + RHSTrunc->getType()->getPrimitiveSizeInBits() <= DstSize) { + LHSTrunc = InsertCastBefore(Instruction::FPExt, LHSTrunc, + CI.getType(), CI); + RHSTrunc = InsertCastBefore(Instruction::FPExt, RHSTrunc, + CI.getType(), CI); + return BinaryOperator::create(OpI->getOpcode(), LHSTrunc, RHSTrunc); + } + } + break; + } + } + return 0; } Instruction *InstCombiner::visitFPExt(CastInst &CI) { diff --git a/test/Transforms/InstCombine/fpextend.ll b/test/Transforms/InstCombine/fpextend.ll new file mode 100644 index 00000000000..5971080cef5 --- /dev/null +++ b/test/Transforms/InstCombine/fpextend.ll @@ -0,0 +1,36 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep fpext +@X = external global float +@Y = external global float + +define void @test() nounwind { +entry: + %tmp = load float* @X, align 4 ; [#uses=1] + %tmp1 = fpext float %tmp to double ; [#uses=1] + %tmp3 = add double %tmp1, 0.000000e+00 ; [#uses=1] + %tmp34 = fptrunc double %tmp3 to float ; [#uses=1] + store float %tmp34, float* @X, align 4 + ret void +} + +define void @test3() nounwind { +entry: + %tmp = load float* @X, align 4 ; [#uses=1] + %tmp1 = fpext float %tmp to double ; [#uses=1] + %tmp2 = load float* @Y, align 4 ; [#uses=1] + %tmp23 = fpext float %tmp2 to double ; [#uses=1] + %tmp5 = fdiv double %tmp1, %tmp23 ; [#uses=1] + %tmp56 = fptrunc double %tmp5 to float ; [#uses=1] + store float %tmp56, float* @X, align 4 + ret void +} + +define void @test4() nounwind { +entry: + %tmp = load float* @X, align 4 ; [#uses=1] + %tmp1 = fpext float %tmp to double ; [#uses=1] + %tmp2 = sub double -0.000000e+00, %tmp1 ; [#uses=1] + %tmp34 = fptrunc double %tmp2 to float ; [#uses=1] + store float %tmp34, float* @X, align 4 + ret void +} +