Index: llvm/trunk/include/llvm/IR/PatternMatch.h =================================================================== --- llvm/trunk/include/llvm/IR/PatternMatch.h +++ llvm/trunk/include/llvm/IR/PatternMatch.h @@ -1555,6 +1555,20 @@ return MaxMin_match(L, R); } +/// Matches FAdd with LHS and RHS in either order. +template +inline BinaryOp_match +m_c_FAdd(const LHS &L, const RHS &R) { + return BinaryOp_match(L, R); +} + +/// Matches FMul with LHS and RHS in either order. +template +inline BinaryOp_match +m_c_FMul(const LHS &L, const RHS &R) { + return BinaryOp_match(L, R); +} + } // end namespace PatternMatch } // end namespace llvm Index: llvm/trunk/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/trunk/lib/Analysis/InstructionSimplify.cpp +++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp @@ -4298,9 +4298,15 @@ if (FMF.noNaNs()) { // X / X -> 1.0 is legal when NaNs are ignored. + // We can ignore infinities because INF/INF is NaN. if (Op0 == Op1) return ConstantFP::get(Op0->getType(), 1.0); + // (X * Y) / Y --> X if we can reassociate to the above form. + Value *X; + if (FMF.allowReassoc() && match(Op0, m_c_FMul(m_Value(X), m_Specific(Op1)))) + return X; + // -X / X -> -1.0 and // X / -X -> -1.0 are legal when NaNs are ignored. // We can ignore signed zeros because +-0.0/+-0.0 is NaN and ignored. Index: llvm/trunk/test/Transforms/InstSimplify/fdiv.ll =================================================================== --- llvm/trunk/test/Transforms/InstSimplify/fdiv.ll +++ llvm/trunk/test/Transforms/InstSimplify/fdiv.ll @@ -34,3 +34,37 @@ %r = fdiv double %X, undef ret double %r } + +define double @fmul_fdiv_common_operand(double %x, double %y) { +; CHECK-LABEL: @fmul_fdiv_common_operand( +; CHECK-NEXT: ret double %x +; + %m = fmul double %x, %y + %d = fdiv reassoc nnan double %m, %y + ret double %d +} + +; Negative test - the fdiv must be reassociative and not allow NaNs. + +define double @fmul_fdiv_common_operand_too_strict(double %x, double %y) { +; CHECK-LABEL: @fmul_fdiv_common_operand_too_strict( +; CHECK-NEXT: [[M:%.*]] = fmul fast double %x, %y +; CHECK-NEXT: [[D:%.*]] = fdiv reassoc double [[M]], %y +; CHECK-NEXT: ret double [[D]] +; + %m = fmul fast double %x, %y + %d = fdiv reassoc double %m, %y + ret double %d +} + +; Commute the fmul operands. Use a vector type to verify that works too. + +define <2 x float> @fmul_fdiv_common_operand_commute_vec(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @fmul_fdiv_common_operand_commute_vec( +; CHECK-NEXT: ret <2 x float> %x +; + %m = fmul <2 x float> %y, %x + %d = fdiv fast <2 x float> %m, %y + ret <2 x float> %d +} +