Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -1013,6 +1013,7 @@ /// LValue CodeGenFunction::EmitLValue(const Expr *E) { ApplyDebugLocation DL(*this, E); + ApplyFPFeatures FPF(Builder, E); switch (E->getStmtClass()) { default: return EmitUnsupportedLValue(E, "l-value expression"); Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -258,6 +258,7 @@ Value *Visit(Expr *E) { ApplyDebugLocation DL(CGF, E); + ApplyFPFeatures FPF(Builder, E); return StmtVisitor::Visit(E); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -3822,6 +3822,25 @@ } }; +/// A RAII to apply the FP features from the expression to the IRBuilder. +struct ApplyFPFeatures : public CGBuilderTy::FastMathFlagGuard { + static Optional getFPFeatures(const Expr *E) { + if (const auto *BO = dyn_cast(E)) + return BO->getFPFeatures(); + else if (const auto *CE = dyn_cast(E)) + return CE->getFPFeatures(); + return None; + } + + ApplyFPFeatures(llvm::IRBuilderBase &Builder, const Expr *E) + : CGBuilderTy::FastMathFlagGuard(Builder) { + if (Optional FPFeatures = getFPFeatures(E)) { + llvm::FastMathFlags FMF = Builder.getFastMathFlags(); + FMF.setAllowContract(FPFeatures->allowFPContractAcrossStatement()); + Builder.setFastMathFlags(FMF); + } + } +}; } // end namespace CodeGen } // end namespace clang 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; +}