Skip to content

Commit a046242

Browse files
authored
[clang] Set correct FPOptions if attribute 'optnone' presents (#85605)
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.
1 parent 561b3de commit a046242

File tree

10 files changed

+158
-3
lines changed

10 files changed

+158
-3
lines changed

clang/include/clang/Basic/LangOptions.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,8 @@ class FPOptions {
878878
/// Return difference with the given option set.
879879
FPOptionsOverride getChangesFrom(const FPOptions &Base) const;
880880

881+
void applyChanges(FPOptionsOverride FPO);
882+
881883
// We can define most of the accessors automatically:
882884
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \
883885
TYPE get##NAME() const { \
@@ -959,6 +961,11 @@ class FPOptionsOverride {
959961
setAllowFPContractAcrossStatement();
960962
}
961963

964+
void setDisallowOptimizations() {
965+
setFPPreciseEnabled(true);
966+
setDisallowFPContract();
967+
}
968+
962969
storage_type getAsOpaqueInt() const {
963970
return (static_cast<storage_type>(Options.getAsOpaqueInt())
964971
<< FPOptions::StorageBitSize) |
@@ -1015,6 +1022,10 @@ inline FPOptionsOverride FPOptions::getChangesFrom(const FPOptions &Base) const
10151022
return getChangesSlow(Base);
10161023
}
10171024

1025+
inline void FPOptions::applyChanges(FPOptionsOverride FPO) {
1026+
*this = FPO.applyOverrides(*this);
1027+
}
1028+
10181029
/// Describes the kind of translation unit being processed.
10191030
enum TranslationUnitKind {
10201031
/// The translation unit is a complete translation unit.

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3084,6 +3084,7 @@ class Sema final : public SemaBase {
30843084
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D,
30853085
SkipBodyInfo *SkipBody = nullptr,
30863086
FnBodyKind BodyKind = FnBodyKind::Other);
3087+
void applyFunctionAttributesBeforeParsingBody(Decl *FD);
30873088

30883089
/// Determine whether we can delay parsing the body of a function or
30893090
/// function template until it is used, assuming we don't care about emitting

clang/lib/Parse/ParseCXXInlineMethods.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
603603
// to be re-used for method bodies as well.
604604
ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
605605
Scope::CompoundStmtScope);
606+
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
607+
606608
Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);
607609

608610
if (Tok.is(tok::kw_try)) {

clang/lib/Parse/ParseObjc.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3736,6 +3736,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
37363736
ParseScope BodyScope(this, (parseMethod ? Scope::ObjCMethodScope : 0) |
37373737
Scope::FnScope | Scope::DeclScope |
37383738
Scope::CompoundStmtScope);
3739+
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
37393740

37403741
// Tell the actions module that we have entered a method or c-function definition
37413742
// with the specified Declarator for the method/function.

clang/lib/Parse/Parser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
14971497
return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
14981498
}
14991499

1500+
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
1501+
15001502
if (Tok.is(tok::kw_try))
15011503
return ParseFunctionTryBlock(Res, BodyScope);
15021504

clang/lib/Sema/SemaDecl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15899,6 +15899,11 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1589915899
FD->setInvalidDecl();
1590015900
return D;
1590115901
}
15902+
15903+
// Some function attributes (like OptimizeNoneAttr) need actions before
15904+
// parsing body started.
15905+
applyFunctionAttributesBeforeParsingBody(D);
15906+
1590215907
// We want to attach documentation to original Decl (which might be
1590315908
// a function template).
1590415909
ActOnDocumentableDecl(D);
@@ -15910,6 +15915,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1591015915
return D;
1591115916
}
1591215917

15918+
void Sema::applyFunctionAttributesBeforeParsingBody(Decl *FD) {
15919+
if (!FD || FD->isInvalidDecl())
15920+
return;
15921+
if (auto *TD = dyn_cast<FunctionTemplateDecl>(FD))
15922+
FD = TD->getTemplatedDecl();
15923+
if (FD && FD->hasAttr<OptimizeNoneAttr>()) {
15924+
FPOptionsOverride FPO;
15925+
FPO.setDisallowOptimizations();
15926+
CurFPFeatures.applyChanges(FPO);
15927+
FpPragmaStack.CurrentValue =
15928+
CurFPFeatures.getChangesFrom(FPOptions(LangOpts));
15929+
}
15930+
}
15931+
1591315932
/// Given the set of return statements within a function body,
1591415933
/// compute the variables that are subject to the named return value
1591515934
/// optimization.

clang/lib/Sema/SemaDeclObjC.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
494494
}
495495
}
496496
}
497+
498+
// Some function attributes (like OptimizeNoneAttr) need actions before
499+
// parsing body started.
500+
applyFunctionAttributesBeforeParsingBody(D);
497501
}
498502

499503
namespace {

clang/test/AST/ast-dump-fpfeatures.cpp

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Test without serialization:
2-
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux -std=c++11 -ast-dump %s \
2+
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux -std=c++11 -fcxx-exceptions -ast-dump %s \
33
// RUN: | FileCheck --strict-whitespace %s
44

55
// Test with serialization:
6-
// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
7-
// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null \
6+
// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -fcxx-exceptions -o %t %s
7+
// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -fcxx-exceptions -ast-dump-all /dev/null \
88
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
99
// RUN: | FileCheck --strict-whitespace %s
1010

@@ -187,3 +187,65 @@ float func_18(float x, float y) {
187187
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward
188188
// CHECK: ReturnStmt
189189
// CHECK: BinaryOperator {{.*}} ConstRoundingMode=downward
190+
191+
#pragma float_control(precise, off)
192+
193+
__attribute__((optnone))
194+
float func_19(float x, float y) {
195+
return x + y;
196+
}
197+
198+
// CHECK-LABEL: FunctionDecl {{.*}} func_19 'float (float, float)'
199+
// CHECK: CompoundStmt {{.*}} MathErrno=1
200+
// CHECK: ReturnStmt
201+
// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
202+
203+
__attribute__((optnone))
204+
float func_20(float x, float y) try {
205+
return x + y;
206+
} catch (...) {
207+
return 1.0;
208+
}
209+
210+
// CHECK-LABEL: FunctionDecl {{.*}} func_20 'float (float, float)'
211+
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
212+
// CHECK: ReturnStmt
213+
// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
214+
215+
struct C21 {
216+
C21(float x, float y);
217+
__attribute__((optnone)) float a_method(float x, float y) {
218+
return x * y;
219+
}
220+
float member;
221+
};
222+
223+
// CHECK-LABEL: CXXMethodDecl {{.*}} a_method 'float (float, float)'
224+
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
225+
// CHECK: ReturnStmt
226+
// CHECK: BinaryOperator {{.*}} 'float' '*' ConstRoundingMode=downward MathErrno=1
227+
228+
__attribute__((optnone)) C21::C21(float x, float y) : member(x + y) {}
229+
230+
// CHECK-LABEL: CXXConstructorDecl {{.*}} C21 'void (float, float)'
231+
// CHECK: CXXCtorInitializer {{.*}} 'member' 'float'
232+
// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
233+
234+
template <typename T>
235+
__attribute__((optnone)) T func_22(T x, T y) {
236+
return x + y;
237+
}
238+
239+
// CHECK-LABEL: FunctionTemplateDecl {{.*}} func_22
240+
// CHECK: FunctionDecl {{.*}} func_22 'T (T, T)'
241+
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
242+
// CHECK: ReturnStmt
243+
// CHECK: BinaryOperator {{.*}} '+' ConstRoundingMode=downward MathErrno=1
244+
// CHECK: FunctionDecl {{.*}} func_22 'float (float, float)'
245+
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
246+
// CHECK: ReturnStmt
247+
// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
248+
249+
float func_23(float x, float y) {
250+
return func_22(x, y);
251+
}

clang/test/AST/ast-dump-fpfeatures.m

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Test without serialization:
2+
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux -ast-dump %s \
3+
// RUN: | FileCheck --strict-whitespace %s
4+
5+
// Test with serialization:
6+
// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
7+
// RUN: %clang_cc1 -x objective-c -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null \
8+
// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
9+
// RUN: | FileCheck --strict-whitespace %s
10+
11+
12+
@interface Adder
13+
- (float) sum: (float)x with: (float)y __attribute((optnone));
14+
@end
15+
16+
#pragma float_control(precise, off)
17+
18+
@implementation Adder
19+
- (float) sum: (float)x with: (float)y __attribute((optnone)) {
20+
return x + y;
21+
}
22+
23+
@end
24+
25+
// CHECK-LABEL: ObjCImplementationDecl {{.*}} Adder
26+
// CHECK: ObjCMethodDecl {{.*}} - sum:with: 'float'
27+
// CHECK: CompoundStmt {{.*}} MathErrno=1
28+
// CHECK-NEXT: ReturnStmt
29+
// CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' MathErrno=1
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux -std=c++11 -fcxx-exceptions -fdelayed-template-parsing -ast-dump %s \
2+
// RUN: | FileCheck %s
3+
4+
#pragma STDC FENV_ROUND FE_DOWNWARD
5+
#pragma float_control(precise, off)
6+
7+
template <typename T>
8+
__attribute__((optnone)) T func_22(T x, T y) {
9+
return x + y;
10+
}
11+
12+
// CHECK-LABEL: FunctionTemplateDecl {{.*}} func_22
13+
// CHECK: FunctionDecl {{.*}} func_22 'T (T, T)'
14+
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
15+
// CHECK: ReturnStmt
16+
// CHECK: BinaryOperator {{.*}} '+' ConstRoundingMode=downward MathErrno=1
17+
// CHECK: FunctionDecl {{.*}} func_22 'float (float, float)'
18+
// CHECK: CompoundStmt {{.*}} ConstRoundingMode=downward MathErrno=1
19+
// CHECK: ReturnStmt
20+
// CHECK: BinaryOperator {{.*}} 'float' '+' ConstRoundingMode=downward MathErrno=1
21+
22+
float func_23(float x, float y) {
23+
return func_22(x, y);
24+
}

0 commit comments

Comments
 (0)