Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -508,6 +508,22 @@ Y = I->getOperand(0); } +/// Detect if one operand is IntrincisInst and other is CallInst +static void detectIntrincisInstWithCallInst(Value *Op0, Value *Op1, + IntrinsicInst *&Intr, CallInst *&Call) { + if ((Call = dyn_cast(Op0))) { + if ((Intr = dyn_cast(Op1))) { + return; + } + } + + if ((Intr = dyn_cast(Op0))) { + if ((Call = dyn_cast(Op1))) { + return; + } + } +} + static bool isFiniteNonZeroFp(Constant *C) { if (C->getType()->isVectorTy()) { for (unsigned I = 0, E = C->getType()->getVectorNumElements(); I != E; @@ -701,6 +717,24 @@ } } + // tan(a) * cos(a) -> sin(a) + if (AllowReassociate) { + CallInst *Tan = nullptr; + IntrinsicInst *Cos = nullptr; + detectIntrincisInstWithCallInst(Op0, Op1, Cos, Tan); + if (Cos && Tan) { + Function *TanCallee = Tan->getCalledFunction(); + StringRef TanName = TanCallee->getName(); + if (Cos->getIntrinsicID() == Intrinsic::cos && TanName == "tan" && + Cos->getArgOperand(0) == Tan->getArgOperand(0)) { + Value *Sin = Intrinsic::getDeclaration(I.getModule(), Intrinsic::sin, I.getType()); + Builder.setFastMathFlags(I.getFastMathFlags()); + Value *SinCall = Builder.CreateCall(Sin, Cos->getArgOperand(0), "sin"); + return replaceInstUsesWith(I, SinCall); + } + } + } + // Under unsafe algebra do: // X * log2(0.5*Y) = X*log2(Y) - X if (AllowReassociate) { Index: test/Transforms/InstCombine/fmul.ll =================================================================== --- test/Transforms/InstCombine/fmul.ll +++ test/Transforms/InstCombine/fmul.ll @@ -181,3 +181,17 @@ %mul = fmul float %x.fabs, %y.fabs ret float %mul } + +; CHECK-LABEL @tan_x_cos( +; CHECK: call fast double @llvm.sin.f64(double %a) +define double @tan_x_cos(double %a) { +entry: + %call = call fast double @tan(double %a) + %0 = call fast double @llvm.cos.f64(double %a) + %mul = fmul fast double %0, %call + ret double %mul +} + +declare double @tan(double) nounwind readnone +declare double @llvm.cos.f64(double) nounwind readnone speculatable +declare double @llvm.sin.f64(double) nounwind readnone speculatable