diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -19,6 +19,7 @@ #include "clang/Basic/CapturedStmt.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" @@ -128,7 +129,11 @@ unsigned : NumStmtBits; - unsigned NumStmts : 32 - NumStmtBits; + /// True if the compound statement has one or more pragmas that set some + /// floating-point features. + unsigned HasFPFeatures : 1; + + unsigned NumStmts : 32 - NumStmtBits - 1; /// The location of the opening "{". SourceLocation LBraceLoc; @@ -1401,36 +1406,59 @@ }; /// CompoundStmt - This represents a group of statements like { stmt stmt }. -class CompoundStmt final : public Stmt, - private llvm::TrailingObjects { +class CompoundStmt final + : public Stmt, + private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; /// The location of the closing "}". LBraceLoc is stored in CompoundStmtBits. SourceLocation RBraceLoc; - CompoundStmt(ArrayRef Stmts, SourceLocation LB, SourceLocation RB); + CompoundStmt(ArrayRef Stmts, FPOptionsOverride FPFeatures, + SourceLocation LB, SourceLocation RB); explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty) {} void setStmts(ArrayRef Stmts); + /// Set FPOptionsOverride in trailing storage. Used only by Serialization. + void setStoredFPFeatures(FPOptionsOverride F) { + assert(hasStoredFPFeatures()); + *getTrailingObjects() = F; + } + + size_t numTrailingObjects(OverloadToken) const { + return CompoundStmtBits.NumStmts; + } + public: static CompoundStmt *Create(const ASTContext &C, ArrayRef Stmts, - SourceLocation LB, SourceLocation RB); + FPOptionsOverride FPFeatures, SourceLocation LB, + SourceLocation RB); // Build an empty compound statement with a location. explicit CompoundStmt(SourceLocation Loc) : Stmt(CompoundStmtClass), RBraceLoc(Loc) { CompoundStmtBits.NumStmts = 0; + CompoundStmtBits.HasFPFeatures = 0; CompoundStmtBits.LBraceLoc = Loc; } // Build an empty compound statement. - static CompoundStmt *CreateEmpty(const ASTContext &C, unsigned NumStmts); + static CompoundStmt *CreateEmpty(const ASTContext &C, unsigned NumStmts, + bool HasFPFeatures); bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } unsigned size() const { return CompoundStmtBits.NumStmts; } + bool hasStoredFPFeatures() const { return CompoundStmtBits.HasFPFeatures; } + + /// Get FPOptionsOverride from trailing storage. + FPOptionsOverride getStoredFPFeatures() const { + assert(hasStoredFPFeatures()); + return *getTrailingObjects(); + } + using body_iterator = Stmt **; using body_range = llvm::iterator_range; diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -246,6 +246,7 @@ void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); void VisitCaseStmt(const CaseStmt *Node); + void VisitCompoundStmt(const CompoundStmt *Node); void VisitConstantExpr(const ConstantExpr *Node); void VisitCallExpr(const CallExpr *Node); void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node); diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -655,6 +655,9 @@ return Opts; } + /// Return difference with the given option set. + FPOptionsOverride diffWith(const FPOptions &Base); + // We can define most of the accessors automatically: #define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ TYPE get##NAME() const { \ @@ -703,6 +706,8 @@ : Options(LO), OverrideMask(OverrideMaskBits) {} FPOptionsOverride(FPOptions FPO) : Options(FPO), OverrideMask(OverrideMaskBits) {} + FPOptionsOverride(FPOptions FPO, FPOptions::storage_type Mask) + : Options(FPO), OverrideMask(Mask) {} bool requiresTrailingStorage() const { return OverrideMask != 0; } diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -74,7 +74,12 @@ /// expression. bool IsStmtExpr; - CompoundScopeInfo(bool IsStmtExpr) : IsStmtExpr(IsStmtExpr) {} + /// FP options at the beginning of the compound statement, prior to + /// any pragma. + FPOptions FPFeatures; + + CompoundScopeInfo(bool IsStmtExpr, FPOptions FPO) + : IsStmtExpr(IsStmtExpr), FPFeatures(FPO) {} void setHasEmptyLoopBodies() { HasEmptyLoopBodies = true; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6300,9 +6300,10 @@ if (!ToRBracLocOrErr) return ToRBracLocOrErr.takeError(); - return CompoundStmt::Create( - Importer.getToContext(), ToStmts, - *ToLBracLocOrErr, *ToRBracLocOrErr); + FPOptionsOverride FPO = + S->hasStoredFPFeatures() ? S->getStoredFPFeatures() : FPOptionsOverride(); + return CompoundStmt::Create(Importer.getToContext(), ToStmts, FPO, + *ToLBracLocOrErr, *ToRBracLocOrErr); } ExpectedStmt ASTNodeImporter::VisitCaseStmt(CaseStmt *S) { diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -361,11 +361,14 @@ return Context.getAllocator().identifyKnownAlignedObject(this); } -CompoundStmt::CompoundStmt(ArrayRef Stmts, SourceLocation LB, - SourceLocation RB) +CompoundStmt::CompoundStmt(ArrayRef Stmts, FPOptionsOverride FPFeatures, + SourceLocation LB, SourceLocation RB) : Stmt(CompoundStmtClass), RBraceLoc(RB) { CompoundStmtBits.NumStmts = Stmts.size(); + CompoundStmtBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); setStmts(Stmts); + if (hasStoredFPFeatures()) + setStoredFPFeatures(FPFeatures); CompoundStmtBits.LBraceLoc = LB; } @@ -377,18 +380,23 @@ } CompoundStmt *CompoundStmt::Create(const ASTContext &C, ArrayRef Stmts, + FPOptionsOverride FPFeatures, SourceLocation LB, SourceLocation RB) { void *Mem = - C.Allocate(totalSizeToAlloc(Stmts.size()), alignof(CompoundStmt)); - return new (Mem) CompoundStmt(Stmts, LB, RB); + C.Allocate(totalSizeToAlloc( + Stmts.size(), FPFeatures.requiresTrailingStorage()), + alignof(CompoundStmt)); + return new (Mem) CompoundStmt(Stmts, FPFeatures, LB, RB); } -CompoundStmt *CompoundStmt::CreateEmpty(const ASTContext &C, - unsigned NumStmts) { - void *Mem = - C.Allocate(totalSizeToAlloc(NumStmts), alignof(CompoundStmt)); +CompoundStmt *CompoundStmt::CreateEmpty(const ASTContext &C, unsigned NumStmts, + bool HasFPFeatures) { + void *Mem = C.Allocate( + totalSizeToAlloc(NumStmts, HasFPFeatures), + alignof(CompoundStmt)); CompoundStmt *New = new (Mem) CompoundStmt(EmptyShell()); New->CompoundStmtBits.NumStmts = NumStmts; + New->CompoundStmtBits.HasFPFeatures = HasFPFeatures; return New; } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2368,3 +2368,9 @@ void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) { dumpName(D); } + +void TextNodeDumper::VisitCompoundStmt(const CompoundStmt *S) { + VisitStmt(S); + if (S->hasStoredFPFeatures()) + printFPOptions(S->getStoredFPFeatures()); +} diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -134,7 +134,8 @@ } CompoundStmt *ASTMaker::makeCompound(ArrayRef Stmts) { - return CompoundStmt::Create(C, Stmts, SourceLocation(), SourceLocation()); + return CompoundStmt::Create(C, Stmts, FPOptionsOverride(), SourceLocation(), + SourceLocation()); } DeclRefExpr *ASTMaker::makeDeclRefExpr( diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -203,6 +203,15 @@ return result; } +FPOptionsOverride FPOptions::diffWith(const FPOptions &Base) { + FPOptions::storage_type OverrideMask = 0; +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + if (get##NAME() != Base.get##NAME()) \ + OverrideMask |= NAME##Mask; +#include "clang/Basic/FPOptions.def" + return FPOptionsOverride(*this, OverrideMask); +} + LLVM_DUMP_METHOD void FPOptions::dump() { #define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ llvm::errs() << "\n " #NAME " " << get##NAME(); diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -238,8 +238,8 @@ auto Loc = S.getResumeExpr()->getExprLoc(); auto *Catch = new (CGF.getContext()) CXXCatchStmt(Loc, /*exDecl=*/nullptr, Coro.ExceptionHandler); - auto *TryBody = - CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), Loc, Loc); + auto *TryBody = CompoundStmt::Create(CGF.getContext(), S.getResumeExpr(), + FPOptionsOverride(), Loc, Loc); TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch); CGF.EnterCXXTryStmt(*TryStmt); } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2231,7 +2231,8 @@ } void Sema::PushCompoundScope(bool IsStmtExpr) { - getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo(IsStmtExpr)); + getCurFunction()->CompoundScopes.push_back( + CompoundScopeInfo(IsStmtExpr, getCurFPFeatures())); } void Sema::PopCompoundScope() { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -15328,8 +15328,8 @@ VK_LValue, Conv->getLocation()); assert(FunctionRef && "Can't refer to __invoke function?"); Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); - Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(), - Conv->getLocation())); + Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(), + Conv->getLocation(), Conv->getLocation())); Conv->markUsed(Context); Conv->setReferenced(); @@ -15383,8 +15383,8 @@ // Set the body of the conversion function. Stmt *ReturnS = Return.get(); - Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(), - Conv->getLocation())); + Conv->setBody(CompoundStmt::Create(Context, ReturnS, FPOptionsOverride(), + Conv->getLocation(), Conv->getLocation())); Conv->markUsed(Context); // We're done; notify the mutation listener, if any. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -7187,8 +7187,9 @@ // a StmtExpr; currently this is only used for asm statements. // This is hacky, either create a new CXXStmtWithTemporaries statement or // a new AsmStmtWithTemporaries. - CompoundStmt *CompStmt = CompoundStmt::Create( - Context, SubStmt, SourceLocation(), SourceLocation()); + CompoundStmt *CompStmt = + CompoundStmt::Create(Context, SubStmt, FPOptionsOverride(), + SourceLocation(), SourceLocation()); Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(), /*FIXME TemplateDepth=*/0); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -14179,8 +14179,8 @@ SmallVector BodyParts; BodyParts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end()); BodyParts.push_back(Inner); - Inner = CompoundStmt::Create(Context, BodyParts, Inner->getBeginLoc(), - Inner->getEndLoc()); + Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(), + Inner->getBeginLoc(), Inner->getEndLoc()); Inner = new (Context) ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr, IncrStmt.get(), Inner, LoopHelper.Init->getBeginLoc(), @@ -14455,8 +14455,9 @@ SmallVector InnerBodyStmts; InnerBodyStmts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end()); InnerBodyStmts.push_back(Body); - CompoundStmt *InnerBody = CompoundStmt::Create( - Context, InnerBodyStmts, Body->getBeginLoc(), Body->getEndLoc()); + CompoundStmt *InnerBody = + CompoundStmt::Create(Context, InnerBodyStmts, FPOptionsOverride(), + Body->getBeginLoc(), Body->getEndLoc()); ForStmt *InnerFor = new (Context) ForStmt(Context, InnerInit.get(), InnerCond.get(), nullptr, InnerIncr.get(), InnerBody, LoopHelper.Init->getBeginLoc(), diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -442,7 +442,16 @@ DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]); } - return CompoundStmt::Create(Context, Elts, L, R); + // Calculate difference between FP options in this compound statement and in + // the enclosing one. If this is a function body, take the difference against + // default options. In this case the difference will indicate options that are + // changed upon entry to the statement. + FPOptions FPO = (getCurFunction()->CompoundScopes.size() == 1) + ? FPOptions(getLangOpts()) + : getCurCompoundScope().FPFeatures; + FPOptionsOverride FPDiff = getCurFPFeatures().diffWith(FPO); + + return CompoundStmt::Create(Context, Elts, FPDiff, L, R); } ExprResult diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -153,9 +153,14 @@ VisitStmt(S); SmallVector Stmts; unsigned NumStmts = Record.readInt(); + unsigned HasFPFeatures = Record.readInt(); + assert(S->hasStoredFPFeatures() == HasFPFeatures); while (NumStmts--) Stmts.push_back(Record.readSubStmt()); S->setStmts(Stmts); + if (HasFPFeatures) + S->setStoredFPFeatures( + FPOptionsOverride::getFromOpaqueInt(Record.readInt())); S->CompoundStmtBits.LBraceLoc = readSourceLocation(); S->RBraceLoc = readSourceLocation(); } @@ -2759,7 +2764,8 @@ case STMT_COMPOUND: S = CompoundStmt::CreateEmpty( - Context, /*NumStmts=*/Record[ASTStmtReader::NumStmtFields]); + Context, /*NumStmts=*/Record[ASTStmtReader::NumStmtFields], + /*HasFPFeatures=*/Record[ASTStmtReader::NumStmtFields + 1]); break; case STMT_CASE: diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -81,8 +81,11 @@ void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) { VisitStmt(S); Record.push_back(S->size()); + Record.push_back(S->hasStoredFPFeatures()); for (auto *CS : S->body()) Record.AddStmt(CS); + if (S->hasStoredFPFeatures()) + Record.push_back(S->getStoredFPFeatures().getAsOpaqueInt()); Record.AddSourceLocation(S->getLBracLoc()); Record.AddSourceLocation(S->getRBracLoc()); Code = serialization::STMT_COMPOUND; diff --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp --- a/clang/test/AST/ast-dump-fpfeatures.cpp +++ b/clang/test/AST/ast-dump-fpfeatures.cpp @@ -141,3 +141,49 @@ // CHECK: CompoundStmt // CHECK-NEXT: ReturnStmt // CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' RoundingMode=towardzero + +float func_16(float x, float y) { +#pragma STDC FENV_ROUND FE_TOWARDZERO + if (x < 0) { +#pragma STDC FENV_ROUND FE_UPWARD + return x - y; + } + return x + y; +} + +// CHECK-LABEL: FunctionDecl {{.*}} func_16 'float (float, float)' +// CHECK: CompoundStmt {{.*}} RoundingMode=towardzero +// CHECK: IfStmt +// CHECK: CompoundStmt {{.*}} RoundingMode=upward +// CHECK: ReturnStmt +// CHECK: BinaryOperator {{.*}} RoundingMode=upward +// CHECK: ReturnStmt +// CHECK: BinaryOperator {{.*}} RoundingMode=towardzero + +float func_17(float x, float y) { +#pragma STDC FENV_ROUND FE_TOWARDZERO + if (x < 0) { +#pragma STDC FENV_ROUND FE_TOWARDZERO + return x - y; + } + return x + y; +} + +// CHECK-LABEL: FunctionDecl {{.*}} func_17 'float (float, float)' +// CHECK: CompoundStmt {{.*}} RoundingMode=towardzero +// CHECK: IfStmt +// CHECK: CompoundStmt {{.*}} +// CHECK: ReturnStmt +// CHECK: BinaryOperator {{.*}} RoundingMode=towardzero +// CHECK: ReturnStmt +// CHECK: BinaryOperator {{.*}} RoundingMode=towardzero + +#pragma STDC FENV_ROUND FE_DOWNWARD +float func_18(float x, float y) { + return x + y; +} + +// CHECK-LABEL: FunctionDecl {{.*}} func_18 'float (float, float)' +// CHECK: CompoundStmt {{.*}} RoundingMode=downward +// CHECK: ReturnStmt +// CHECK: BinaryOperator {{.*}} RoundingMode=downward