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 CXXBoolLiteralExprBitfields { 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 @@ -178,6 +178,34 @@ FEA_On }; + // Values of the following enumerations correspond to metadata arguments + // specified for constrained floating-point intrinsics: + // http://llvm.org/docs/LangRef.html#constrained-floating-point-intrinsics. + + /// Possible rounding modes. + enum FPRoundingModeKind { + /// Rounding to nearest, corresponds to "round.tonearest". + FPR_ToNearest, + /// Rounding toward -Inf, corresponds to "round.downward". + FPR_Downward, + /// Rounding toward +Inf, corresponds to "round.upward". + FPR_Upward, + /// Rounding toward zero, corresponds to "round.towardzero". + FPR_TowardZero, + /// Is determined by runtime environment, corresponds to "round.dynamic". + FPR_Dynamic + }; + + /// Possible floating point exception behavior. + enum FPExceptionModeKind { + /// Assume that floating-point exceptions are masked. + FPE_Ignore, + /// Transformations do not cause new exceptions but may hide some. + FPE_MayTrap, + /// Strictly preserve the floating-point exception semantics. + FPE_Strict + }; + public: /// Set of enabled sanitizers. @@ -307,17 +335,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 { @@ -348,14 +384,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 @@ -1258,12 +1258,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; @@ -8759,6 +8759,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 @@ -998,9 +998,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 @@ -935,6 +935,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 @@ -9698,7 +9698,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(), @@ -10180,7 +10180,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(),