Index: clang/lib/Lex/PPMacroExpansion.cpp =================================================================== --- clang/lib/Lex/PPMacroExpansion.cpp +++ clang/lib/Lex/PPMacroExpansion.cpp @@ -1577,14 +1577,35 @@ Tok.setKind(tok::string_literal); } else if (II == Ident__FLT_EVAL_METHOD__) { // __FLT_EVAL_METHOD__ is set to the default value. - OS << getTUFPEvalMethod(); - // __FLT_EVAL_METHOD__ expands to a simple numeric value. - Tok.setKind(tok::numeric_constant); - if (getLastFPEvalPragmaLocation().isValid()) { - // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is altered - // by the pragma. - Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); - Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); + if (getTUFPEvalMethod() == + LangOptions::FPEvalMethodKind::FEM_Indeterminable) { + // This is possible if we are in a `fast-math` mode (set either + // via a command line option or via a `pragam float_conntrol` or a + // `pragma clang fp eval-method`. + // __FLT_EVAL_METHOD__ expands to -1. + // The `minus` operator is the next token we read from the stream. + auto Toks = std::make_unique(2); + OS << "-"; + Tok.setKind(tok::minus); + // Push the token `1` to the stream. + Token NumberToken; + NumberToken.startToken(); + NumberToken.setKind(tok::numeric_constant); + NumberToken.setLiteralData("1"); + NumberToken.setLength(1); + Toks[0] = NumberToken; + EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion*/ false, + /*IsReinject*/ false); + } else { + OS << getTUFPEvalMethod(); + // __FLT_EVAL_METHOD__ expands to a simple numeric value. + Tok.setKind(tok::numeric_constant); + if (getLastFPEvalPragmaLocation().isValid()) { + // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is + // altered by the pragma. + Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); + Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); + } } } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -254,6 +254,10 @@ PP.setCurrentFPEvalMethod(SourceLocation(), getLangOpts().getFPEvalMethod()); CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod()); + // Fast-math is enabled. + if (getLangOpts().AllowFPReassoc || getLangOpts().AllowRecip) + PP.setCurrentFPEvalMethod(SourceLocation(), + LangOptions::FEM_Indeterminable); } // Anchor Sema's type info to this TU. Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -517,6 +517,9 @@ else NewFPFeatures.setFPPreciseEnabled(false); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); + // Fast-math is enabled. + PP.setCurrentFPEvalMethod( + Loc, LangOptions::FPEvalMethodKind::FEM_Indeterminable); break; case PFC_Except: if (!isPreciseFPEnabled()) @@ -540,6 +543,8 @@ } FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); NewFPFeatures = FpPragmaStack.CurrentValue; + PP.setCurrentFPEvalMethod(SourceLocation(), + CurFPFeatures.getFPEvalMethod()); break; } CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); Index: clang/test/CodeGen/eval-method-fast-math.c =================================================================== --- /dev/null +++ clang/test/CodeGen/eval-method-fast-math.c @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK + +// RUN: %clang_cc1 -triple i386--linux -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK-EXT + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -mreassociate -freciprocal-math -ffp-contract=fast \ +// RUN: -ffast-math -triple x86_64-linux-gnu \ +// RUN: -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK-FAST + +// RUN: %clang_cc1 -triple i386--linux -mreassociate -freciprocal-math \ +// RUN: -ffp-contract=fast -ffast-math -emit-llvm -o - %s \ +// RUN: | FileCheck %s -check-prefixes=CHECK-FAST + +float res; +int add(float a, float b, float c) { + // CHECK: fadd float + // CHECK: load float, float* + // CHECK: fadd float + // CHECK: store float + // CHECK-FAST: fadd fast float + // CHECK-FAST: load float, float* + // CHECK-FAST: fadd fast float + // CHECK: ret i32 0 + // CHECK-EXT: ret i32 2 + // CHECK-FAST: ret i32 -1 + res = a + b + c; + return __FLT_EVAL_METHOD__; +} + +int add_precise(float a, float b, float c) { +#pragma float_control(precise, on) + // CHECK: fadd float + // CHECK: load float, float* + // CHECK: fadd float + // CHECK: store float + // CHECK: ret i32 0 + // CHECK-FAST: ret i32 -1 + res = a + b + c; + return __FLT_EVAL_METHOD__; +} + +#pragma float_control(push) +#pragma float_control(precise, on) +int add_precise_1(float a, float b, float c) { + // CHECK: fadd float + // CHECK: load float, float* + // CHECK: fadd float + // CHECK: store float + // CHECK: ret i32 0 + // CHECK-FAST: ret i32 -1 + res = a + b + c; + return __FLT_EVAL_METHOD__; +} +#pragma float_control(pop) + +int add_not_precise(float a, float b, float c) { + // Fast-math is enabled with this pragma. +#pragma float_control(precise, off) + // CHECK-FAST: fadd fast float + // CHECK-FAST: load float, float* + // CHECK-FAST: fadd fast float + // CHECK-FAST: ret i32 -1 + res = a + b + c; + return __FLT_EVAL_METHOD__; +} + +#pragma float_control(push) +// Fast-math is enabled with this pragma. +#pragma float_control(precise, off) +int add_not_precise_1(float a, float b, float c) { + // CHECK-FAST: fadd fast float + // CHECK-FAST: load float, float* + // CHECK-FAST: fadd fast float + // CHECK-FAST: ret i32 -1 + res = a + b + c; + return __FLT_EVAL_METHOD__; +} +#pragma float_control(pop) + +int getFPEvalMethod() { + // CHECK: ret i32 0 + return __FLT_EVAL_METHOD__; +}