Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -113,6 +113,22 @@ (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize; } +/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions. +static void updateFastMathFlags(llvm::FastMathFlags &FMF, + FPOptions FPFeatures) { + FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement()); +} + +/// Propagate fast-math flags from \p Op to the instruction in \p V. +static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) { + if (auto *I = dyn_cast(V)) { + llvm::FastMathFlags FMF = I->getFastMathFlags(); + updateFastMathFlags(FMF, Op.FPFeatures); + I->setFastMathFlags(FMF); + } + return V; +} + class ScalarExprEmitter : public StmtVisitor { CodeGenFunction &CGF; @@ -553,8 +569,10 @@ !CanElideOverflowCheck(CGF.getContext(), Ops)) return EmitOverflowCheckedBinOp(Ops); - if (Ops.LHS->getType()->isFPOrFPVectorTy()) - return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); + if (Ops.LHS->getType()->isFPOrFPVectorTy()) { + Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); + return propagateFMFlags(V, Ops); + } return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } /// Create a binary op that checks for overflow. @@ -2722,7 +2740,8 @@ if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder)) return FMulAdd; - return Builder.CreateFAdd(op.LHS, op.RHS, "add"); + Value *V = Builder.CreateFAdd(op.LHS, op.RHS, "add"); + return propagateFMFlags(V, op); } return Builder.CreateAdd(op.LHS, op.RHS, "add"); @@ -2755,7 +2774,8 @@ // Try to form an fmuladd. if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) return FMulAdd; - return Builder.CreateFSub(op.LHS, op.RHS, "sub"); + Value *V = Builder.CreateFSub(op.LHS, op.RHS, "sub"); + return propagateFMFlags(V, op); } return Builder.CreateSub(op.LHS, op.RHS, "sub"); Index: test/CodeGen/ffp-contract-fast-option.cpp =================================================================== --- /dev/null +++ test/CodeGen/ffp-contract-fast-option.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s + +float fp_contract_1(float a, float b, float c) { + // CHECK-LABEL: fp_contract_1fff( + // CHECK: fmul contract float + // CHECK: fadd contract float + return a * b + c; +} + +float fp_contract_2(float a, float b, float c) { + // CHECK-LABEL: fp_contract_2fff( + // CHECK: fmul contract float + // CHECK: fsub contract float + return a * b - c; +} + +void fp_contract_3(float *a, float b, float c) { + // CHECK-LABEL: fp_contract_3Pfff( + // CHECK: fmul contract float + // CHECK: fadd contract float + a[0] += b * c; +} + +void fp_contract_4(float *a, float b, float c) { + // CHECK-LABEL: fp_contract_4Pfff( + // CHECK: fmul contract float + // CHECK: fsub contract float + a[0] -= b * c; +}