mibintc updated this revision to Diff 240245.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D72841/new/
https://reviews.llvm.org/D72841
Files:
clang/docs/LanguageExtensions.rst
clang/include/clang/AST/Stmt.h
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Basic/PragmaKinds.h
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CGExprScalar.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/Parse/ParsePragma.cpp
clang/lib/Parse/ParseStmt.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/CodeGen/fp-floatcontrol-class.cpp
clang/test/CodeGen/fp-floatcontrol-pragma.cpp
clang/test/CodeGen/fp-floatcontrol-stack.cpp
clang/test/Parser/fp-floatcontrol-syntax.cpp
llvm/include/llvm/IR/IRBuilder.h
Index: llvm/include/llvm/IR/IRBuilder.h
===================================================================
--- llvm/include/llvm/IR/IRBuilder.h
+++ llvm/include/llvm/IR/IRBuilder.h
@@ -299,10 +299,16 @@
IRBuilderBase &Builder;
FastMathFlags FMF;
MDNode *FPMathTag;
+ bool IsFPConstrained;
+ fp::ExceptionBehavior DefaultConstrainedExcept;
+ fp::RoundingMode DefaultConstrainedRounding;
public:
FastMathFlagGuard(IRBuilderBase &B)
- : Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag) {}
+ : Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag),
+ IsFPConstrained(B.IsFPConstrained),
+ DefaultConstrainedExcept(B.DefaultConstrainedExcept),
+ DefaultConstrainedRounding(B.DefaultConstrainedRounding) {}
FastMathFlagGuard(const FastMathFlagGuard &) = delete;
FastMathFlagGuard &operator=(const FastMathFlagGuard &) = delete;
@@ -310,6 +316,9 @@
~FastMathFlagGuard() {
Builder.FMF = FMF;
Builder.DefaultFPMathTag = FPMathTag;
+ Builder.IsFPConstrained = IsFPConstrained;
+ Builder.DefaultConstrainedExcept = DefaultConstrainedExcept;
+ Builder.DefaultConstrainedRounding = DefaultConstrainedRounding;
}
};
Index: clang/test/Parser/fp-floatcontrol-syntax.cpp
===================================================================
--- /dev/null
+++ clang/test/Parser/fp-floatcontrol-syntax.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -DCHECK_ERROR %s
+// XFAIL: *
+
+float function_scope(float a) {
+ return a;
+}
+
+// There seems to be a bug in Actions.CurContext->isTranslationUnit()
+// unless this dummy class is used. FIXME Fix the issue then remove this
+// workaround.
+#define TU_WORKAROUND
+#ifdef TU_WORKAROUND
+class ResetTUScope;
+#endif
+#ifdef CHECK_ERROR
+# pragma float_control(push)
+# pragma float_control(pop)
+# pragma float_control(precise,on,push)
+void check_stack() {
+#pragma float_control(push) // expected-error {{can only appear at file scope}}
+#pragma float_control(pop) // expected-error {{can only appear at file scope}}
+#pragma float_control(precise,on,push) // expected-error {{can only appear at file scope}}
+ return;
+}
+#endif
Index: clang/test/CodeGen/fp-floatcontrol-stack.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fp-floatcontrol-stack.cpp
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -DDEFAULT=1 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
+// RUN: %clang_cc1 -DEBSTRICT=1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
+
+#define FUN(n) (float z) { return n * z + n; }
+
+float fun_default FUN(1)
+//CHECK-LABEL: define {{.*}} @_Z11fun_defaultf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+//CHECK-DDEFAULT: fadd float
+#endif
+#if EBSTRICT
+// Note that backend wants constrained intrinsics used "everywhere"
+// if they have been requested on the command line, so fp operations
+// will be built with constrained intrinsics and default settings
+// for exception behavior and rounding mode.
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+#endif
+class ResetScope;
+
+#pragma float_control(except, on, push)
+float exc_on FUN(2)
+//CHECK-LABEL: define {{.*}} @_Z6exc_onf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.experimental.constrained.fmul{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+#endif
+
+class ResetScope;
+#pragma float_control(pop)
+float exc_pop FUN(5)
+//CHECK-LABEL: define {{.*}} @_Z7exc_popf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+//CHECK-DDEFAULT: fadd float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+#endif
+
+class ResetScope;
+#pragma float_control(except, off)
+float exc_off FUN(5)
+//CHECK-LABEL: define {{.*}} @_Z7exc_offf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+//CHECK-DDEFAULT: fadd float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(precise, on, push)
+float precise_on FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z10precise_onf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//Usually 'precise' forces the creation of fmuladd but I believe
+//the backend doesn't yet support a constrained fmuladd.
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(pop)
+float precise_pop FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z11precise_popf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+//CHECK-DDEFAULT: fadd float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(precise, off)
+float precise_off FUN(4)
+//CHECK-LABEL: define {{.*}} @_Z11precise_offf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+//CHECK-DDEFAULT: fadd float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(precise, on)
+float precise_on2 FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z11precise_on2f{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(push)
+float precise_push FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z12precise_pushf{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(precise, off)
+float precise_off2 FUN(4)
+//CHECK-LABEL: define {{.*}} @_Z12precise_off2f{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+//CHECK-DDEFAULT: fadd float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+#pragma float_control(pop)
+float precise_pop2 FUN(3)
+//CHECK-LABEL: define {{.*}} @_Z12precise_pop2f{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}ignore
+#endif
+
+class ResetScope;
+// --------- end of push pop test
+#pragma float_control(except, on)
+float y();
+class ON {
+float z = y() * 1;
+//CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
+#endif
+};
+ON on;
+#pragma float_control( except, off)
+class OFF {
+float w = y() * 1;
+//CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
+#if DEFAULT
+//CHECK-DDEFAULT: fmul float
+#endif
+#if EBSTRICT
+//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}ignore
+#endif
+};
+OFF off;
+
Index: clang/test/CodeGen/fp-floatcontrol-pragma.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fp-floatcontrol-pragma.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+float fff(float x, float y) {
+// CHECK-LABEL: define float @_Z3fffff{{.*}}
+// CHECK: entry
+#pragma float_control(except, on)
+ float z;
+ z = z*z;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ {
+ z = x*y;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ }
+ {
+// This pragma has no effect since if there are any fp intrin in the
+// function then all the operations need to be fp intrin
+#pragma float_control(except, off)
+ z = z + x*y;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ }
+ z = z*z;
+//CHECK: llvm.experimental.constrained.fmul{{.*}}
+ return z;
+}
+float check_precise(float x, float y) {
+// CHECK-LABEL: define float @_Z13check_preciseff{{.*}}
+ float z;
+ {
+#pragma float_control(precise, on)
+ z = x*y + z;
+//CHECK: llvm.fmuladd{{.*}}
+ }
+ {
+#pragma float_control(precise, off)
+ z = x*y + z;
+//CHECK: fmul float
+//CHECK: fadd float
+ }
+ return z;
+}
+float fma_test1(float a, float b, float c) {
+// CHECK-LABEL define float @_Z9fma_test1fff{{.*}}
+#pragma float_control(precise, on)
+ float x = a * b + c;
+//CHECK: fmuladd
+ return x;
+}
Index: clang/test/CodeGen/fp-floatcontrol-class.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/fp-floatcontrol-class.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+#pragma float_control(except, on)
+float y();
+class ON {
+float z = y() * 1;
+// CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
+// float_control does not pertain to initializer expressions
+//CHECK: fmul float
+};
+ON on;
+#pragma float_control( except, off)
+class OFF {
+float w = y() * 1;
+// CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
+//CHECK: fmul float
+};
+OFF off;
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -13131,10 +13131,15 @@
return ExprError();
if (ResultTy->isRealFloatingType() &&
- (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
+ ((FpPragmaStack.CurrentValue.HasPragma &&
+ FpPragmaStack.CurrentValue.IsExcept) ||
+ getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
// Mark the current function as usng floating point constrained intrinsics
if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
+ // The pragma's do not pertain to expressions that
+ // occur, for example, inside an internal global_var_init_function
+ // (In this case, the CurContext function decl is null.)
F->setUsesFPIntrin(true);
}
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -407,6 +407,37 @@
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
}
+void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
+ PragmaMsStackAction Action,
+ PragmaFloatControlKind Value) {
+ auto NewValue = FpPragmaStack.CurrentValue;
+ NewValue.HasPragma = true;
+ switch(Value) {
+ default:
+ llvm_unreachable("invalid pragma float_control kind");
+ case PFC_Precise:
+ NewValue.IsPrecise = true;
+ break;
+ case PFC_NoPrecise:
+ NewValue.IsPrecise = false;
+ break;
+ case PFC_Except:
+ NewValue.IsExcept = true;
+ break;
+ case PFC_NoExcept:
+ NewValue.IsExcept = false;
+ break;
+ case PFC_Push:
+ case PFC_Pop:
+ break;
+ }
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ NewValue = FpPragmaStack.CurrentValue;
+ FPFeatures.setFPPreciseEnabled(NewValue.IsPrecise);
+ FPFeatures.setFPExcept(NewValue.IsExcept ?
+ LangOptions::FPE_Strict : LangOptions::FPE_Ignore);
+}
+
void Sema::ActOnPragmaMSPointersToMembers(
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
SourceLocation PragmaLoc) {
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -140,6 +140,8 @@
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
+ FpPragmaStack({false, false, pp.getLangOpts().getFPExceptionMode() ==
+ LangOptions::FPE_Strict}),
PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -753,6 +753,9 @@
case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess();
return nullptr;
+ case tok::annot_pragma_float_control:
+ HandlePragmaFloatControl();
+ return nullptr;
case tok::annot_pragma_fp:
HandlePragmaFP();
break;
Index: clang/lib/Parse/ParseStmt.cpp
===================================================================
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -353,13 +353,13 @@
case tok::annot_pragma_fp_contract:
ProhibitAttributes(Attrs);
- Diag(Tok, diag::err_pragma_fp_contract_scope);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
ConsumeAnnotationToken();
return StmtError();
case tok::annot_pragma_fp:
ProhibitAttributes(Attrs);
- Diag(Tok, diag::err_pragma_fp_scope);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
ConsumeAnnotationToken();
return StmtError();
@@ -368,6 +368,12 @@
HandlePragmaFEnvAccess();
return StmtEmpty();
+ case tok::annot_pragma_float_control:
+ ProhibitAttributes(Attrs);
+ Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
+ ConsumeAnnotationToken();
+ return StmtError();
+
case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
@@ -936,6 +942,9 @@
case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess();
break;
+ case tok::annot_pragma_float_control:
+ HandlePragmaFloatControl();
+ break;
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -184,6 +184,16 @@
Sema &Actions;
};
+struct PragmaFloatControlHandler : public PragmaHandler {
+ PragmaFloatControlHandler(Sema &Actions)
+ : PragmaHandler("float_control"), Actions(Actions) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &FirstToken) override;
+
+private:
+ Sema &Actions;
+};
+
struct PragmaMSPointersToMembers : public PragmaHandler {
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
@@ -322,6 +332,9 @@
PP.AddPragmaHandler(MSCommentHandler.get());
}
+ FloatControlHandler =
+ std::make_unique<PragmaFloatControlHandler>(Actions);
+ PP.AddPragmaHandler(FloatControlHandler.get());
if (getLangOpts().MicrosoftExt) {
MSDetectMismatchHandler =
std::make_unique<PragmaDetectMismatchHandler>(Actions);
@@ -420,6 +433,8 @@
PP.RemovePragmaHandler("clang", PCSectionHandler.get());
PCSectionHandler.reset();
+ PP.RemovePragmaHandler(FloatControlHandler.get());
+ FloatControlHandler.reset();
if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
@@ -622,6 +637,18 @@
ConsumeAnnotationToken();
}
+void Parser::HandlePragmaFloatControl() {
+ assert(Tok.is(tok::annot_pragma_float_control));
+
+ uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
+ Sema::PragmaMsStackAction Action =
+ static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
+ PragmaFloatControlKind Kind =
+ PragmaFloatControlKind(Value & 0xFFFF);
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
+ Actions.ActOnPragmaFloatControl(PragmaLoc, Action, Kind);
+}
+
void Parser::HandlePragmaFEnvAccess() {
assert(Tok.is(tok::annot_pragma_fenv_access));
tok::OnOffSwitch OOS =
@@ -2465,6 +2492,139 @@
PP.EnterToken(AnnotTok, /*IsReinject*/ false);
}
+/// Handle the \#pragma float_control extension.
+///
+/// The syntax is:
+/// \code
+/// #pragma float_control(keyword[, setting] [,push])
+/// \endcode
+/// Where 'keyword' and 'setting' are identifiers.
+// 'keyword' can be: precise, except, push, pop
+// 'setting' can be: on, off
+/// The optional arguments 'setting' and 'push' are supported only
+/// when the keyword is 'precise' or 'except'.
+void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducer Introducer,
+ Token &Tok) {
+ Sema::PragmaMsStackAction Action = Sema::PSK_Set;
+ SourceLocation FloatControlLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(FloatControlLoc, diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ // Read the identifier.
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+
+ // Verify that this is one of the float control options.
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ PragmaFloatControlKind Kind =
+ llvm::StringSwitch<PragmaFloatControlKind>(
+ II->getName())
+ .Case("precise", PFC_Precise)
+ .Case("except", PFC_Except)
+ .Case("push", PFC_Push)
+ .Case("pop", PFC_Pop)
+ .Default(PFC_Unknown);
+ PP.Lex(Tok); // the identifier
+ if (Kind == PFC_Unknown) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_unknown_kind);
+ return;
+ } else if (Kind == PFC_Push ||
+ Kind == PFC_Pop) {
+ if (Actions.getCurScope()->getParent() != nullptr) {
+ // FIXME this doesn't detect file-scope:
+ // the token immediately following a function definition
+ // returns false, but the token immediately following a forward
+ // class declaration returns true
+ //FIXME PP.Diag(Tok.getLocation(), diag::err_pragma_fc_pp_scope);
+ return;
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // Eat the r_paren
+ Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push;
+ } else {
+ if (Tok.is(tok::r_paren))
+ // Selecting Precise or Except
+ PP.Lex(Tok); // the r_paren
+ else if (Tok.isNot(tok::comma)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ } else {
+ PP.Lex(Tok); // ,
+ if (!Tok.isAnyIdentifier()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ StringRef PushOnOff = Tok.getIdentifierInfo()->getName();
+ if (PushOnOff == "on")
+ // Kind is set correctly
+ ;
+ else if (PushOnOff == "off") {
+ if (Kind == PFC_Precise )
+ Kind = PFC_NoPrecise ;
+ if (Kind == PFC_Except )
+ Kind = PFC_NoExcept ;
+ } else if (PushOnOff == "push") {
+ if (!Actions.CurContext->isTranslationUnit()) {
+ //FIXME PP.Diag(Tok.getLocation(), diag::err_pragma_fc_pp_scope);
+ return;
+ }
+ Action = Sema::PSK_Push_Set;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // the identifier
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ if (!Tok.isAnyIdentifier()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ StringRef ExpectedPush = Tok.getIdentifierInfo()->getName();
+ if (ExpectedPush == "push") {
+ if (!Actions.CurContext->isTranslationUnit()) {
+ //FIXME PP.Diag(Tok.getLocation(), diag::err_pragma_fc_pp_scope);
+ return;
+ }
+ Action = Sema::PSK_Push_Set;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // the push identifier
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
+ return;
+ }
+ PP.Lex(Tok); // the r_paren
+ }
+ }
+ SourceLocation EndLoc = Tok.getLocation();
+
+ // Note: there is no accomodation for PP callback for this pragma.
+
+ // Enter the annotation.
+ Token AnnotTok;
+ AnnotTok.startToken();
+ AnnotTok.setKind(tok::annot_pragma_float_control);
+ AnnotTok.setLocation(FloatControlLoc);
+ AnnotTok.setAnnotationEndLoc(EndLoc);
+ AnnotTok.setAnnotationValue(reinterpret_cast<void *>(
+ static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF))));
+ PP.EnterToken(AnnotTok, /*IsReinject=*/false);
+}
+
/// Handle the Microsoft \#pragma detect_mismatch extension.
///
/// The syntax is:
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -4418,6 +4418,16 @@
}
} // end namespace CodeGen
+
+// Map the LangOption for floating point rounding mode into
+// the corresponding enum in the IR.
+llvm::fp::RoundingMode ToConstrainedRoundingMD(
+ LangOptions::FPRoundingModeKind Kind);
+
+// Map the LangOption for floating point exception behavior into
+// the corresponding enum in the IR.
+llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
+ LangOptions::FPExceptionModeKind Kind);
} // end namespace clang
#endif
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -108,7 +108,7 @@
// Map the LangOption for rounding mode into
// the corresponding enum in the IR.
-static llvm::fp::RoundingMode ToConstrainedRoundingMD(
+llvm::fp::RoundingMode clang::ToConstrainedRoundingMD(
LangOptions::FPRoundingModeKind Kind) {
switch (Kind) {
@@ -123,7 +123,7 @@
// Map the LangOption for exception behavior into
// the corresponding enum in the IR.
-static llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
+llvm::fp::ExceptionBehavior clang::ToConstrainedExceptMD(
LangOptions::FPExceptionModeKind Kind) {
switch (Kind) {
@@ -140,14 +140,14 @@
auto fpExceptionBehavior = ToConstrainedExceptMD(
getLangOpts().getFPExceptionMode());
+ Builder.setDefaultConstrainedRounding(fpRoundingMode);
+ Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
if (fpExceptionBehavior == llvm::fp::ebIgnore &&
fpRoundingMode == llvm::fp::rmToNearest)
// Constrained intrinsics are not used.
- ;
+ Builder.setIsFPConstrained(false);
else {
Builder.setIsFPConstrained(true);
- Builder.setDefaultConstrainedRounding(fpRoundingMode);
- Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
}
}
@@ -1258,6 +1258,9 @@
FunctionArgList Args;
QualType ResTy = BuildFunctionArgList(GD, Args);
+ if (FD->usesFPIntrin())
+ Builder.setIsFPConstrained(true);
+
// Check if we should generate debug info for this function.
if (FD->hasAttr<NoDebugAttr>())
DebugInfo = nullptr; // disable debug info indefinitely for this function
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -423,6 +423,29 @@
Value *Visit(Expr *E) {
ApplyDebugLocation DL(CGF, E);
+ if (BinaryOperator * BinOp = dyn_cast<BinaryOperator>(E)) {
+ // Preserve the old values
+ llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
+
+ auto RoundingBehavior = Builder.getDefaultConstrainedRounding();
+ auto NewExceptionBehavior = ToConstrainedExceptMD(
+ BinOp->getFPFeatures().fpExcept());
+ Builder.setDefaultConstrainedExcept(NewExceptionBehavior);
+ if (BinOp->getFPFeatures().fpPreciseEnabled()) {
+ Builder.clearFastMathFlags();
+ assert(BinOp->getFPFeatures().allowFPContractWithinStatement() &&
+ "Expected FPFeatures to allow constract within statement");
+ }
+ assert((CGF.CurFuncDecl==nullptr ||
+ Builder.getIsFPConstrained() ||
+ isa<CXXConstructorDecl>(CGF.CurFuncDecl) ||
+ isa<CXXDestructorDecl>(CGF.CurFuncDecl) ||
+ (NewExceptionBehavior == llvm::fp::ebIgnore &&
+ RoundingBehavior == llvm::fp::rmToNearest)) &&
+ "FPConstrained should be enabled on entire function");
+
+ return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
+ }
return StmtVisitor<ScalarExprEmitter, Value*>::Visit(E);
}
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1748,6 +1748,10 @@
if (CodeGenOpts.NullPointerIsValid)
FuncAttrs.addAttribute("null-pointer-is-valid", "true");
+ if (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
+ getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore)
+ FuncAttrs.addAttribute(llvm::Attribute::StrictFP);
+
// TODO: Omit attribute when the default is IEEE.
if (CodeGenOpts.FPDenormalMode != llvm::DenormalMode::Invalid)
FuncAttrs.addAttribute("denormal-fp-math",
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -541,6 +541,22 @@
PragmaStack<StringLiteral *> ConstSegStack;
PragmaStack<StringLiteral *> CodeSegStack;
+ class FpPragmaStateType {
+ public:
+ bool HasPragma;
+ bool IsPrecise;
+ bool IsExcept;
+ FpPragmaStateType() : HasPragma(false), IsPrecise(false), IsExcept(false){};
+ explicit FpPragmaStateType(unsigned I) :
+ HasPragma(I & 0B100), IsPrecise(I & 0B10), IsExcept(I & 0B01) {};
+ FpPragmaStateType(bool HasPragma, bool IsPrecise, bool IsExcept) :
+ HasPragma(HasPragma), IsPrecise(IsPrecise), IsExcept(IsExcept){};
+ unsigned getInt() const {
+ return (HasPragma<<2) | (IsPrecise << 1) | IsExcept;
+ }
+ };
+ PragmaStack<FpPragmaStateType> FpPragmaStack;
+
// RAII object to push / pop sentinel slots for all MS #pragma stacks.
// Actions should be performed only if we enter / exit a C++ method body.
class PragmaStackSentinelRAII {
@@ -9312,6 +9328,11 @@
void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
StringRef Value);
+ /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control
+ void ActOnPragmaFloatControl(SourceLocation Loc,
+ PragmaMsStackAction Action,
+ PragmaFloatControlKind Value);
+
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
void ActOnPragmaUnused(const Token &Identifier,
Scope *curScope,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -178,6 +178,7 @@
std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
+ std::unique_ptr<PragmaHandler> FloatControlHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers;
std::unique_ptr<PragmaHandler> MSVtorDisp;
std::unique_ptr<PragmaHandler> MSInitSeg;
@@ -719,6 +720,10 @@
/// #pragma STDC FENV_ACCESS...
void HandlePragmaFEnvAccess();
+ /// Handle the annotation token produced for
+ /// #pragma float_control
+ void HandlePragmaFloatControl();
+
/// \brief Handle the annotation token produced for
/// #pragma clang fp ...
void HandlePragmaFP();
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -806,6 +806,11 @@
// handles them.
PRAGMA_ANNOTATION(pragma_fenv_access)
+// Annotation for #pragma float_control
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+PRAGMA_ANNOTATION(pragma_float_control)
+
// Annotation for #pragma pointers_to_members...
// The lexer produces these so that they only take effect when the parser
// handles them.
Index: clang/include/clang/Basic/PragmaKinds.h
===================================================================
--- clang/include/clang/Basic/PragmaKinds.h
+++ clang/include/clang/Basic/PragmaKinds.h
@@ -25,6 +25,16 @@
PMSST_ON // #pragms ms_struct on
};
+enum PragmaFloatControlKind {
+ PFC_Unknown,
+ PFC_Precise, // #pragma float_control(precise, [,on])
+ PFC_NoPrecise, // #pragma float_control(precise, off)
+ PFC_Except, // #pragma float_control(except [,on])
+ PFC_NoExcept, // #pragma float_control(except, off)
+ PFC_Push, // #pragma float_control(push)
+ PFC_Pop // #pragma float_control(pop)
+};
+
}
#endif
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -357,18 +357,24 @@
class FPOptions {
public:
FPOptions() : fp_contract(LangOptions::FPC_Off),
- fenv_access(LangOptions::FEA_Off) {}
+ fenv_access(LangOptions::FEA_Off),
+ fp_except(LangOptions::FPE_Ignore),
+ fp_precise(false) {}
// Used for serializing.
explicit FPOptions(unsigned I)
: fp_contract(static_cast<LangOptions::FPContractModeKind>(I & 3)),
- fenv_access(static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1))
- {}
+ fenv_access(static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1)),
+ fp_except(static_cast<LangOptions::FPExceptionModeKind>((I >> 3) & 3)),
+ fp_precise(static_cast<bool>((I >> 5) & 1)) {}
explicit FPOptions(const LangOptions &LangOpts)
: fp_contract(LangOpts.getDefaultFPContractMode()),
- fenv_access(LangOptions::FEA_Off) {}
+ fenv_access(LangOptions::FEA_Off),
// FIXME: Use getDefaultFEnvAccessMode() when available.
+ fp_except(LangOpts.getFPExceptionMode()),
+ fp_precise(!LangOpts.OpenCL && !LangOpts.FastMath &&
+ LangOpts.getDefaultFPContractMode() == LangOptions::FPC_On) {}
bool allowFPContractWithinStatement() const {
return fp_contract == LangOptions::FPC_On;
@@ -396,16 +402,37 @@
fenv_access = LangOptions::FEA_On;
}
+ void setFPPreciseEnabled(bool Value) {
+ fp_precise = Value;
+
+ /* Precise mode implies fp_contract and disables ffast-math */
+ if (fp_precise)
+ setAllowFPContractWithinStatement();
+ else
+ setDisallowFPContract();
+ }
+ bool fpPreciseEnabled() { return fp_precise; }
+
+ void setFPExcept(LangOptions::FPExceptionModeKind Value) { fp_except = Value;}
+ LangOptions::FPExceptionModeKind fpExcept() {
+ return static_cast<LangOptions::FPExceptionModeKind>(fp_except);
+ }
+
void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
/// Used to serialize this.
- unsigned getInt() const { return fp_contract | (fenv_access << 2); }
+ unsigned getInt() const {
+ return fp_contract | (fenv_access << 2) |
+ (fp_except << 3) | (fp_precise << 5);
+ };
private:
/// Adjust BinaryOperator::FPFeatures to match the total bit-field size
/// of these two.
unsigned fp_contract : 2;
unsigned fenv_access : 1;
+ unsigned fp_except : 2;
+ unsigned fp_precise : 1;
};
/// Describes the kind of translation unit being processed.
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1108,8 +1108,8 @@
"Microsoft environment">,
InGroup<IgnoredPragmas>;
// - #pragma fp_contract
-def err_pragma_fp_contract_scope : Error<
- "'#pragma fp_contract' can only appear at file scope or at the start of a "
+def err_pragma_file_or_compound_scope : Error<
+ "'#pragma %0' can only appear at file scope or at the start of a "
"compound statement">;
// - #pragma stdc unknown
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
@@ -1128,6 +1128,11 @@
def err_pragma_detect_mismatch_malformed : Error<
"pragma detect_mismatch is malformed; it requires two comma-separated "
"string literals">;
+// - #pragma float_control
+def err_pragma_float_control_malformed : Error<
+ "pragma float_control is malformed; it requires one or two comma-separated "
+ "arguments">;
+def err_pragma_float_control_unknown_kind : Error<"unknown kind of pragma float control">;
// - #pragma pointers_to_members
def err_pragma_pointers_to_members_unknown_kind : Error<
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
@@ -1295,9 +1300,8 @@
def err_pragma_fp_invalid_argument : Error<
"unexpected argument '%0' to '#pragma clang fp %1'; "
"expected 'on', 'fast' or 'off'">;
-def err_pragma_fp_scope : Error<
- "'#pragma clang fp' can only appear at file scope or at the start of a "
- "compound statement">;
+def err_pragma_fc_pp_scope : Error<
+ "'#pragma float_control push/pop' can only appear at file scope">;
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -530,7 +530,7 @@
/// This is only meaningful for operations on floating point
/// types and 0 otherwise.
- unsigned FPFeatures : 3;
+ unsigned FPFeatures : 6;
SourceLocation OpLoc;
};
@@ -601,7 +601,7 @@
unsigned OperatorKind : 6;
// Only meaningful for floating point types.
- unsigned FPFeatures : 3;
+ unsigned FPFeatures : 6;
};
class CXXRewrittenBinaryOperatorBitfields {
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -3028,6 +3028,35 @@
section of the code. This can be useful when fast contraction is otherwise
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
+The ``#pragma float_control`` pragma allows precise floating-point
+semantics and floating-point exception behavior to be specified
+for a section of the source code. This pragma can only appear at file scope or
+at the start of a compound statement (excluding comments). When using within a
+compound statement, the pragma is active within the scope of the compound
+statement. This pragma is modeled after a Microsoft pragma with the
+same spelling and syntax. For pragmas specified at file scope, a stack
+is supported so that the pragma float_control settings can be pushed or popped.
+
+When ``float_control(precise, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line option ``ffp-model=precise``
+is enabled. That is, fast-math is disabled and fp-contract=on (fused
+multiple add) is enabled.
+
+When ``float_control(except, on)`` is enabled, the section of code governed
+by the pragma behaves as though the command-line
+ ``ffp-exception-behavior=strict`` is enabled, ``float-control(precise, off)``
+selects ``ffp-exception-behavior=ignore``.
+
+The full syntax this pragma supports is ``float_control(except|precise, on|off, [push])`` and ``float_control(push|pop)``. The ``push`` and ``pop`` forms can only occur at file scope.
+
+.. code-block:: c++
+
+ for(...) {
+ // This block will be compiled with fno-fast-math and ffp-contract=on
+ #pragma float_control(precise, on)
+ a = b[i] * c[i] + e;
+ }
+
Specifying an attribute for multiple declarations (#pragma clang attribute)
===========================================================================
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits