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 @@ -530,7 +530,7 @@ /// This is only meaningful for operations on floating point /// types and 0 otherwise. - unsigned FPFeatures : 3; + unsigned FPFeatures : 8; SourceLocation OpLoc; }; @@ -601,7 +601,7 @@ unsigned OperatorKind : 6; // Only meaningful for floating point types. - unsigned FPFeatures : 3; + unsigned FPFeatures : 8; }; class CXXRewrittenBinaryOperatorBitfields { 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 @@ -357,17 +357,25 @@ class FPOptions { public: FPOptions() : fp_contract(LangOptions::FPC_Off), - fenv_access(LangOptions::FEA_Off) {} + fenv_access(LangOptions::FEA_Off), + rounding(LangOptions::FPR_ToNearest), + exceptions(LangOptions::FPE_Ignore) + {} // Used for serializing. explicit FPOptions(unsigned I) : fp_contract(static_cast(I & 3)), - fenv_access(static_cast((I >> 2) & 1)) + fenv_access(static_cast((I >> 2) & 1)), + rounding(static_cast((I >> 3) & 7)), + exceptions(static_cast((I >> 6) & 3)) {} explicit FPOptions(const LangOptions &LangOpts) : fp_contract(LangOpts.getDefaultFPContractMode()), - fenv_access(LangOptions::FEA_Off) {} + fenv_access(LangOptions::FEA_Off), + rounding(LangOptions::FPR_ToNearest), + exceptions(LangOptions::FPE_Ignore) + {} // FIXME: Use getDefaultFEnvAccessMode() when available. bool allowFPContractWithinStatement() const { @@ -398,14 +406,42 @@ void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; } + LangOptions::FPRoundingModeKind getRoundingMode() const { + return static_cast(rounding); + } + + void setRoundingMode(LangOptions::FPRoundingModeKind RM) { + rounding = RM; + } + + LangOptions::FPExceptionModeKind getExceptionMode() const { + return static_cast(exceptions); + } + + void setExceptionMode(LangOptions::FPExceptionModeKind EM) { + exceptions = EM; + } + + bool isFPConstrained() const { + return getRoundingMode() != LangOptions::FPR_ToNearest || + getExceptionMode() != LangOptions::FPE_Ignore || + allowFEnvAccess(); + } + /// Used to serialize this. - unsigned getInt() const { return fp_contract | (fenv_access << 2); } + unsigned getInt() const { + return fp_contract | (fenv_access << 2) | (rounding << 3) + | (exceptions << 6); + } private: - /// Adjust BinaryOperator::FPFeatures to match the total bit-field size - /// of these two. + /// Adjust BinaryOperatorBitfields::FPFeatures and + /// CXXOperatorCallExprBitfields::FPFeatures to match the total bit-field size + /// of these fields. unsigned fp_contract : 2; unsigned fenv_access : 1; + unsigned rounding : 3; + unsigned exceptions : 2; }; /// Describes the kind of translation unit being processed. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1306,12 +1306,12 @@ /// should not be used elsewhere. void EmitCurrentDiagnostic(unsigned DiagID); - /// Records and restores the FP_CONTRACT state on entry/exit of compound + /// Records and restores the FPFeatures state on entry/exit of compound /// statements. - class FPContractStateRAII { + class FPFeaturesStateRAII { public: - FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {} - ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; } + FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {} + ~FPFeaturesStateRAII() { S.FPFeatures = OldFPFeaturesState; } private: Sema& S; @@ -9409,6 +9409,12 @@ /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC); + /// Called to set rounding mode for floating point operations. + void setRoundingMode(LangOptions::FPRoundingModeKind); + + /// Called to set exception behavior for floating point operations. + void setExceptionMode(LangOptions::FPExceptionModeKind); + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. void AddAlignmentAttributesForRecord(RecordDecl *RD); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1014,9 +1014,9 @@ Tok.getLocation(), "in compound statement ('{}')"); - // Record the state of the FP_CONTRACT pragma, restore on leaving the + // Record the state of the FPFeatures, restore on leaving the // compound statement. - Sema::FPContractStateRAII SaveFPContractState(Actions); + Sema::FPFeaturesStateRAII SaveFPContractState(Actions); InMessageExpressionRAIIObject InMessage(*this, false); BalancedDelimiterTracker T(*this, tok::l_brace); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -940,6 +940,14 @@ } } +void Sema::setRoundingMode(LangOptions::FPRoundingModeKind FPR) { + FPFeatures.setRoundingMode(FPR); +} + +void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) { + FPFeatures.setExceptionMode(FPE); +} + void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) { switch (FPC) { case LangOptions::FEA_On: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9938,7 +9938,7 @@ RHS.get() == E->getRHS()) return E; - Sema::FPContractStateRAII FPContractState(getSema()); + Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); getSema().FPFeatures = E->getFPFeatures(); return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), @@ -10464,7 +10464,7 @@ (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) return SemaRef.MaybeBindToTemporary(E); - Sema::FPContractStateRAII FPContractState(getSema()); + Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); getSema().FPFeatures = E->getFPFeatures(); return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),