[clang] [clang] Set correct FPOptions if attribute 'optnone' presents (PR #85605)
Serge Pavlov via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 20 10:22:17 PDT 2024
https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/85605
>From 5049e0209e240f0f8a3ccb6e248d55d1480b7bad Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Mon, 18 Mar 2024 13:20:15 +0700
Subject: [PATCH 1/2] [clang] Set correct FPOptions if attribute 'optnone'
presents
Attribute `optnone` must turn off all optimizations including fast-math
ones. Actually AST nodes in the 'optnone' function still had fast-math
flags. This change implements fixing FP options before function body is
parsed.
---
clang/include/clang/Basic/LangOptions.h | 11 +++++++++++
clang/include/clang/Sema/Sema.h | 1 +
clang/lib/Parse/ParseStmt.cpp | 4 ++++
clang/lib/Sema/SemaDecl.cpp | 10 ++++++++++
clang/test/AST/ast-dump-fpfeatures.cpp | 11 +++++++++++
5 files changed, 37 insertions(+)
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 08fc706e3cbf74..19c60a8cb5e946 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -842,6 +842,8 @@ class FPOptions {
/// Return difference with the given option set.
FPOptionsOverride getChangesFrom(const FPOptions &Base) const;
+ void applyChanges(FPOptionsOverride FPO);
+
// We can define most of the accessors automatically:
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
TYPE get##NAME() const { \
@@ -923,6 +925,11 @@ class FPOptionsOverride {
setAllowFPContractAcrossStatement();
}
+ void setDisallowOptimizations() {
+ setFPPreciseEnabled(true);
+ setDisallowFPContract();
+ }
+
storage_type getAsOpaqueInt() const {
return (static_cast<storage_type>(Options.getAsOpaqueInt())
<< FPOptions::StorageBitSize) |
@@ -979,6 +986,10 @@ inline FPOptionsOverride FPOptions::getChangesFrom(const FPOptions &Base) const
return getChangesSlow(Base);
}
+inline void FPOptions::applyChanges(FPOptionsOverride FPO) {
+ *this = FPO.applyOverrides(*this);
+}
+
/// Describes the kind of translation unit being processed.
enum TranslationUnitKind {
/// The translation unit is a complete translation unit.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 95ea5ebc7f1ac1..ccc2ded67589ec 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3222,6 +3222,7 @@ class Sema final {
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D,
SkipBodyInfo *SkipBody = nullptr,
FnBodyKind BodyKind = FnBodyKind::Other);
+ void applyFunctionAttributesBeforeParsingBody(Decl *FD);
/// Determine whether we can delay parsing the body of a function or
/// function template until it is used, assuming we don't care about emitting
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 76a3fa8f2627de..489ae9f167b95d 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2508,6 +2508,10 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
Sema::PragmaStackSentinelRAII
PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
+ // Some function attributes (like OptimizeNoneAttr) affect FP options.
+ Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
+ Actions.applyFunctionAttributesBeforeParsingBody(Decl);
+
// Do not enter a scope for the brace, as the arguments are in the same scope
// (the function body) as the body itself. Instead, just read the statement
// list and put it into a CompoundStmt for safe keeping.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5850cd0ab6b9aa..1f52f5e57e5376 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15919,6 +15919,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
return D;
}
+void Sema::applyFunctionAttributesBeforeParsingBody(Decl *FD) {
+ if (FD && FD->hasAttr<OptimizeNoneAttr>()) {
+ FPOptionsOverride FPO;
+ FPO.setDisallowOptimizations();
+ CurFPFeatures.applyChanges(FPO);
+ FpPragmaStack.CurrentValue =
+ CurFPFeatures.getChangesFrom(FPOptions(LangOpts));
+ }
+}
+
/// Given the set of return statements within a function body,
/// compute the variables that are subject to the named return value
/// optimization.
diff --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp
index da0011602a728e..5eda5528c07018 100644
--- a/clang/test/AST/ast-dump-fpfeatures.cpp
+++ b/clang/test/AST/ast-dump-fpfeatures.cpp
@@ -187,3 +187,14 @@ float func_18(float x, float y) {
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward
// CHECK: ReturnStmt
// CHECK: BinaryOperator {{.*}} ConstRoundingMode=downward
+
+#pragma float_control(precise, off)
+__attribute__((optnone))
+float func_19(float x, float y) {
+ return x + y;
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} func_19 'float (float, float)'
+// CHECK: CompoundStmt {{.*}} MathErrno=1
+// CHECK: ReturnStmt
+// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
>From 52755f263b992ba2add370319cea9cb5c5d8cda6 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Wed, 20 Mar 2024 23:22:49 +0700
Subject: [PATCH 2/2] Support more cases of function body
---
clang/lib/Parse/ParseStmt.cpp | 4 ----
clang/lib/Parse/Parser.cpp | 4 ++++
clang/test/AST/ast-dump-fpfeatures.cpp | 30 +++++++++++++++++++++++---
3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 489ae9f167b95d..76a3fa8f2627de 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2508,10 +2508,6 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
Sema::PragmaStackSentinelRAII
PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
- // Some function attributes (like OptimizeNoneAttr) affect FP options.
- Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
- Actions.applyFunctionAttributesBeforeParsingBody(Decl);
-
// Do not enter a scope for the brace, as the arguments are in the same scope
// (the function body) as the body itself. Instead, just read the statement
// list and put it into a CompoundStmt for safe keeping.
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index cc0e41ed221c4f..e4b8757c38f7f4 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1495,6 +1495,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
}
+ // Some function attributes (like OptimizeNoneAttr) affect FP options.
+ Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
+ Actions.applyFunctionAttributesBeforeParsingBody(Res);
+
if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res, BodyScope);
diff --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp
index 5eda5528c07018..68499539c1ed19 100644
--- a/clang/test/AST/ast-dump-fpfeatures.cpp
+++ b/clang/test/AST/ast-dump-fpfeatures.cpp
@@ -1,10 +1,10 @@
// Test without serialization:
-// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux -std=c++11 -ast-dump %s \
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux -std=c++11 -fcxx-exceptions -ast-dump %s \
// RUN: | FileCheck --strict-whitespace %s
// Test with serialization:
-// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
-// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null \
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -fcxx-exceptions -o %t %s
+// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -fcxx-exceptions -ast-dump-all /dev/null \
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
// RUN: | FileCheck --strict-whitespace %s
@@ -189,6 +189,7 @@ float func_18(float x, float y) {
// CHECK: BinaryOperator {{.*}} ConstRoundingMode=downward
#pragma float_control(precise, off)
+
__attribute__((optnone))
float func_19(float x, float y) {
return x + y;
@@ -198,3 +199,26 @@ float func_19(float x, float y) {
// CHECK: CompoundStmt {{.*}} MathErrno=1
// CHECK: ReturnStmt
// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
+
+__attribute__((optnone))
+float func_20(float x, float y) try {
+ return x + y;
+} catch (...) {
+ return 1.0;
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} func_20 'float (float, float)'
+// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
+// CHECK: ReturnStmt
+// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
+
+struct C21 {
+ C21(float x, float y);
+ float member;
+};
+
+__attribute__((optnone)) C21::C21(float x, float y) : member(x + y) {}
+
+// CHECK-LABEL: CXXConstructorDecl {{.*}} C21 'void (float, float)'
+// CHECK: CXXCtorInitializer {{.*}} 'member' 'float'
+// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
More information about the cfe-commits
mailing list