diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2118,21 +2118,21 @@ /// class UnaryOperator final : public Expr, - private llvm::TrailingObjects { + private llvm::TrailingObjects { Stmt *Val; - size_t numTrailingObjects(OverloadToken) const { + size_t numTrailingObjects(OverloadToken) const { return UnaryOperatorBits.HasFPFeatures ? 1 : 0; } - FPOptions &getTrailingFPFeatures() { + FPOptionsOverride &getTrailingFPFeatures() { assert(UnaryOperatorBits.HasFPFeatures); - return *getTrailingObjects(); + return *getTrailingObjects(); } - const FPOptions &getTrailingFPFeatures() const { + const FPOptionsOverride &getTrailingFPFeatures() const { assert(UnaryOperatorBits.HasFPFeatures); - return *getTrailingObjects(); + return *getTrailingObjects(); } public: @@ -2141,7 +2141,7 @@ protected: UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, - bool CanOverflow, FPOptions FPFeatures); + bool CanOverflow, FPOptionsOverride FPFeatures); /// Build an empty unary operator. explicit UnaryOperator(bool HasFPFeatures, EmptyShell Empty) @@ -2156,7 +2156,7 @@ static UnaryOperator *Create(const ASTContext &C, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, - bool CanOverflow, FPOptions FPFeatures); + bool CanOverflow, FPOptionsOverride FPFeatures); Opcode getOpcode() const { return static_cast(UnaryOperatorBits.Opc); @@ -2182,13 +2182,13 @@ // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { - return getFPFeatures(LO).allowFPContractWithinStatement(); + return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); } // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. bool isFEnvAccessOn(const LangOptions &LO) const { - return getFPFeatures(LO).allowFEnvAccess(); + return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } /// isPostfix - Return true if this is a postfix operation, like x++. @@ -2263,19 +2263,26 @@ protected: /// Get FPFeatures from trailing storage - FPOptions getStoredFPFeatures() const { return getTrailingFPFeatures(); } + FPOptionsOverride getStoredFPFeatures() const { + return getTrailingFPFeatures(); + } /// Set FPFeatures in trailing storage, used only by Serialization - void setStoredFPFeatures(FPOptions F) { getTrailingFPFeatures() = F; } + void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; } public: // Get the FP features status of this operator. Only meaningful for // operations on floating point types. - FPOptions getFPFeatures(const LangOptions &LO) const { + FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (UnaryOperatorBits.HasFPFeatures) - return getStoredFPFeatures(); + return getStoredFPFeatures().applyOverrides(LO); return FPOptions::defaultWithoutTrailingStorage(LO); } + FPOptionsOverride getFPOptionsOverride() const { + if (UnaryOperatorBits.HasFPFeatures) + return getStoredFPFeatures(); + return FPOptionsOverride(); + } friend TrailingObjects; friend class ASTReader; @@ -3633,14 +3640,14 @@ size_t offsetOfTrailingStorage() const; /// Return a pointer to the trailing FPOptions - FPOptions *getTrailingFPFeatures() { + FPOptionsOverride *getTrailingFPFeatures() { assert(BinaryOperatorBits.HasFPFeatures); - return reinterpret_cast(reinterpret_cast(this) + - offsetOfTrailingStorage()); + return reinterpret_cast( + reinterpret_cast(this) + offsetOfTrailingStorage()); } - const FPOptions *getTrailingFPFeatures() const { + const FPOptionsOverride *getTrailingFPFeatures() const { assert(BinaryOperatorBits.HasFPFeatures); - return reinterpret_cast( + return reinterpret_cast( reinterpret_cast(this) + offsetOfTrailingStorage()); } @@ -3648,7 +3655,7 @@ /// allocated for the trailing objects when needed. BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, - SourceLocation opLoc, FPOptions FPFeatures); + SourceLocation opLoc, FPOptionsOverride FPFeatures); /// Construct an empty binary operator. explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) { @@ -3661,7 +3668,7 @@ static BinaryOperator *Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, - FPOptions FPFeatures); + FPOptionsOverride FPFeatures); SourceLocation getExprLoc() const { return getOperatorLoc(); } SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; } void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; } @@ -3808,40 +3815,48 @@ bool hasStoredFPFeatures() const { return BinaryOperatorBits.HasFPFeatures; } /// Get FPFeatures from trailing storage - FPOptions getStoredFPFeatures() const { + FPOptionsOverride getStoredFPFeatures() const { assert(hasStoredFPFeatures()); return *getTrailingFPFeatures(); } /// Set FPFeatures in trailing storage, used only by Serialization - void setStoredFPFeatures(FPOptions F) { + void setStoredFPFeatures(FPOptionsOverride F) { assert(BinaryOperatorBits.HasFPFeatures); *getTrailingFPFeatures() = F; } // Get the FP features status of this operator. Only meaningful for // operations on floating point types. - FPOptions getFPFeatures(const LangOptions &LO) const { + FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (BinaryOperatorBits.HasFPFeatures) - return getStoredFPFeatures(); + return getStoredFPFeatures().applyOverrides(LO); return FPOptions::defaultWithoutTrailingStorage(LO); } + // This is used in ASTImporter + FPOptionsOverride getFPFeatures(const LangOptions &LO) const { + if (BinaryOperatorBits.HasFPFeatures) + return getStoredFPFeatures(); + return FPOptionsOverride(); + } + // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { - return getFPFeatures(LO).allowFPContractWithinStatement(); + return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); } // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. bool isFEnvAccessOn(const LangOptions &LO) const { - return getFPFeatures(LO).allowFEnvAccess(); + return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } protected: BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, - SourceLocation opLoc, FPOptions FPFeatures, bool dead2); + SourceLocation opLoc, FPOptionsOverride FPFeatures, + bool dead2); /// Construct an empty BinaryOperator, SC is CompoundAssignOperator. BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { @@ -3851,7 +3866,7 @@ /// Return the size in bytes needed for the trailing objects. /// Used to allocate the right amount of storage. static unsigned sizeOfTrailingObjects(bool HasFPFeatures) { - return HasFPFeatures * sizeof(FPOptions); + return HasFPFeatures * sizeof(FPOptionsOverride); } }; @@ -3873,7 +3888,7 @@ protected: CompoundAssignOperator(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, ExprValueKind VK, ExprObjectKind OK, - SourceLocation OpLoc, FPOptions FPFeatures, + SourceLocation OpLoc, FPOptionsOverride FPFeatures, QualType CompLHSType, QualType CompResultType) : BinaryOperator(C, lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures, true), @@ -3889,7 +3904,7 @@ static CompoundAssignOperator * Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, - FPOptions FPFeatures, QualType CompLHSType = QualType(), + FPOptionsOverride FPFeatures, QualType CompLHSType = QualType(), QualType CompResultType = QualType()); // The two computation types are the type the LHS is converted diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -84,6 +84,7 @@ friend class ASTStmtWriter; SourceRange Range; + FPOptionsOverride Overrides; // CXXOperatorCallExpr has some trailing objects belonging // to CallExpr. See CallExpr for the details. @@ -92,7 +93,7 @@ CXXOperatorCallExpr(OverloadedOperatorKind OpKind, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, - SourceLocation OperatorLoc, FPOptions FPFeatures, + SourceLocation OperatorLoc, FPOptionsOverride FPFeatures, ADLCallKind UsesADL); CXXOperatorCallExpr(unsigned NumArgs, EmptyShell Empty); @@ -101,7 +102,7 @@ static CXXOperatorCallExpr * Create(const ASTContext &Ctx, OverloadedOperatorKind OpKind, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, - SourceLocation OperatorLoc, FPOptions FPFeatures, + SourceLocation OperatorLoc, FPOptionsOverride FPFeatures, ADLCallKind UsesADL = NotADL); static CXXOperatorCallExpr *CreateEmpty(const ASTContext &Ctx, @@ -164,20 +165,10 @@ return T->getStmtClass() == CXXOperatorCallExprClass; } - // Set the FP contractability status of this operator. Only meaningful for + // Set the FPFeatures status of this operator. Only meaningful for // operations on floating point types. - void setFPFeatures(FPOptions F) { - CXXOperatorCallExprBits.FPFeatures = F.getAsOpaqueInt(); - } - FPOptions getFPFeatures() const { - return FPOptions(CXXOperatorCallExprBits.FPFeatures); - } - - // Get the FP contractability status of this operator. Only meaningful for - // operations on floating point types. - bool isFPContractableWithinStatement() const { - return getFPFeatures().allowFPContractWithinStatement(); - } + void setFPFeatures(FPOptionsOverride F) { Overrides = F; } + FPOptionsOverride getFPFeatures() const { return Overrides; } }; /// Represents a call to a member function that 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 @@ -614,9 +614,6 @@ /// The kind of this overloaded operator. One of the enumerator /// value of OverloadedOperatorKind. unsigned OperatorKind : 6; - - // Only meaningful for floating point types. - unsigned FPFeatures : 14; }; class CXXRewrittenBinaryOperatorBitfields { diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/FPOptions.def @@ -0,0 +1,26 @@ +//===--- FPOptions.def - Floating Point Options database --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// This file defines the Floating Point language options. Users of this file +// must define the FPOPT macro to make use of this information. +#ifndef OPTION +# error Define the OPTION macro to handle floating point language options +#endif + +// OPTION(name, type, width, previousName) +OPTION(FPContractMode, LangOptions::FPModeKind, 2, First) +OPTION(RoundingMode, RoundingMode, 3, FPContractMode) +OPTION(FPExceptionMode, LangOptions::FPExceptionModeKind, 2, RoundingMode) +OPTION(AllowFEnvAccess, bool, 1, FPExceptionMode) +OPTION(AllowFPReassociate, bool, 1, AllowFEnvAccess) +OPTION(NoHonorNaNs, bool, 1, AllowFPReassociate) +OPTION(NoHonorInfs, bool, 1, NoHonorNaNs) +OPTION(NoSignedZero, bool, 1, NoHonorInfs) +OPTION(AllowReciprocal, bool, 1, NoSignedZero) +OPTION(AllowApproxFunc, bool, 1, AllowReciprocal) +#undef OPTION 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 @@ -366,175 +366,175 @@ }; /// Floating point control options +class FPOptionsOverride; class FPOptions { +public: + // We start by defining the layout. + using storage_type = uint16_t; + using RoundingMode = llvm::RoundingMode; -public: - FPOptions() - : fp_contract(LangOptions::FPM_Off), fenv_access(LangOptions::FPM_Off), - rounding(LangOptions::FPR_ToNearest), - exceptions(LangOptions::FPE_Ignore), allow_reassoc(0), no_nans(0), - no_infs(0), no_signed_zeros(0), allow_reciprocal(0), approx_func(0) {} + // Define a fake option named "First" so that we have a PREVIOUS even for the + // real first option. + static constexpr storage_type FirstShift = 0, FirstWidth = 0; +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + static constexpr storage_type NAME##Shift = \ + PREVIOUS##Shift + PREVIOUS##Width; \ + static constexpr storage_type NAME##Width = WIDTH; \ + static constexpr storage_type NAME##Mask = ((1 << NAME##Width) - 1) \ + << NAME##Shift; +#include "clang/Basic/FPOptions.def" +private: + storage_type Value; + +public: + FPOptions() : Value(0) { + setFPContractMode(LangOptions::FPM_Off); + setRoundingMode(static_cast(LangOptions::FPR_ToNearest)); + setFPExceptionMode(LangOptions::FPE_Ignore); + } // Used for serializing. explicit FPOptions(unsigned I) { getFromOpaqueInt(I); } - explicit FPOptions(const LangOptions &LangOpts) - : fp_contract(LangOpts.getDefaultFPContractMode()), - fenv_access(LangOptions::FPM_Off), - rounding(static_cast(LangOpts.getFPRoundingMode())), - exceptions(LangOpts.getFPExceptionMode()), - allow_reassoc(LangOpts.AllowFPReassoc), no_nans(LangOpts.NoHonorNaNs), - no_infs(LangOpts.NoHonorInfs), no_signed_zeros(LangOpts.NoSignedZero), - allow_reciprocal(LangOpts.AllowRecip), - approx_func(LangOpts.ApproxFunc) {} - // FIXME: Use getDefaultFEnvAccessMode() when available. - - void setFastMath(bool B = true) { - allow_reassoc = no_nans = no_infs = no_signed_zeros = approx_func = - allow_reciprocal = B; + explicit FPOptions(const LangOptions &LO) { + setFPContractMode(LO.getDefaultFPContractMode()); + setRoundingMode(LO.getFPRoundingMode()); + setFPExceptionMode(LO.getFPExceptionMode()); + setAllowFEnvAccess(LangOptions::FPM_Off), + setAllowFPReassociate(LO.AllowFPReassoc); + setNoHonorNaNs(LO.NoHonorNaNs); + setNoHonorInfs(LO.NoHonorInfs); + setNoSignedZero(LO.NoSignedZero); + setAllowReciprocal(LO.AllowRecip); + setAllowApproxFunc(LO.ApproxFunc); } - /// Return the default value of FPOptions that's used when trailing - /// storage isn't required. - static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO); - - /// Does this FPOptions require trailing storage when stored in various - /// AST nodes, or can it be recreated using `defaultWithoutTrailingStorage`? - bool requiresTrailingStorage(const LangOptions &LO); - bool allowFPContractWithinStatement() const { - return fp_contract == LangOptions::FPM_On; + return getFPContractMode() == LangOptions::FPM_On; + } + void setAllowFPContractWithinStatement() { + setFPContractMode(LangOptions::FPM_On); } bool allowFPContractAcrossStatement() const { - return fp_contract == LangOptions::FPM_Fast; + return getFPContractMode() == LangOptions::FPM_Fast; } - - void setAllowFPContractWithinStatement() { - fp_contract = LangOptions::FPM_On; + void setAllowFPContractAcrossStatement() { + setFPContractMode(LangOptions::FPM_Fast); } - void setAllowFPContractAcrossStatement() { - fp_contract = LangOptions::FPM_Fast; + bool isFPConstrained() const { + return getRoundingMode() != + static_cast(RoundingMode::NearestTiesToEven) || + getFPExceptionMode() != LangOptions::FPE_Ignore || + getAllowFEnvAccess(); } - void setDisallowFPContract() { fp_contract = LangOptions::FPM_Off; } + bool operator==(FPOptions other) const { return Value == other.Value; } - bool allowFEnvAccess() const { return fenv_access == LangOptions::FPM_On; } + /// Return the default value of FPOptions that's used when trailing + /// storage isn't required. + static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO); - void setAllowFEnvAccess() { fenv_access = LangOptions::FPM_On; } + storage_type getAsOpaqueInt() const { return Value; } + void getFromOpaqueInt(storage_type value) { Value = value; } - void setFPPreciseEnabled(bool Value) { - if (Value) { - /* Precise mode implies fp_contract=on and disables ffast-math */ - setFastMath(false); - setAllowFPContractWithinStatement(); - } else { - /* Precise mode implies fp_contract=fast and enables ffast-math */ - setFastMath(true); - setAllowFPContractAcrossStatement(); - } + // We can define most of the accessors automatically: +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + unsigned get##NAME() const { \ + return static_cast(TYPE((Value & NAME##Mask) >> NAME##Shift)); \ + } \ + void set##NAME(TYPE value) { \ + Value = (Value & ~NAME##Mask) | (storage_type(value) << NAME##Shift); \ } +#include "clang/Basic/FPOptions.def" + LLVM_DUMP_METHOD void dump(); +}; - void setDisallowFEnvAccess() { fenv_access = LangOptions::FPM_Off; } +/// The FPOptions override type is value of the new FPOptions +/// plus a mask showing which fields are actually set in it: +class FPOptionsOverride { + FPOptions Options; + FPOptions::storage_type OverrideMask = 0; - RoundingMode getRoundingMode() const { - return static_cast(rounding); - } +public: + using RoundingMode = llvm::RoundingMode; + FPOptionsOverride() {} - void setRoundingMode(RoundingMode RM) { - rounding = static_cast(RM); - } + // Used for serializing. + explicit FPOptionsOverride(unsigned I) { getFromOpaqueInt(I); } + + bool requiresTrailingStorage() const { return OverrideMask != 0; } - LangOptions::FPExceptionModeKind getExceptionMode() const { - return static_cast(exceptions); + void setAllowFPContractWithinStatement() { + setFPContractModeOverride(LangOptions::FPM_On); } - void setExceptionMode(LangOptions::FPExceptionModeKind EM) { - exceptions = EM; + void setAllowFPContractAcrossStatement() { + setFPContractModeOverride(LangOptions::FPM_Fast); } - /// FMF Flag queries - bool allowAssociativeMath() const { return allow_reassoc; } - bool noHonorNaNs() const { return no_nans; } - bool noHonorInfs() const { return no_infs; } - bool noSignedZeros() const { return no_signed_zeros; } - bool allowReciprocalMath() const { return allow_reciprocal; } - bool allowApproximateFunctions() const { return approx_func; } - - /// Flag setters - void setAllowAssociativeMath(bool B = true) { allow_reassoc = B; } - void setNoHonorNaNs(bool B = true) { no_nans = B; } - void setNoHonorInfs(bool B = true) { no_infs = B; } - void setNoSignedZeros(bool B = true) { no_signed_zeros = B; } - void setAllowReciprocalMath(bool B = true) { allow_reciprocal = B; } - void setAllowApproximateFunctions(bool B = true) { approx_func = B; } + void setDisallowFPContract() { + setFPContractModeOverride(LangOptions::FPM_Off); + } - bool isFPConstrained() const { - return getRoundingMode() != RoundingMode::NearestTiesToEven || - getExceptionMode() != LangOptions::FPE_Ignore || - allowFEnvAccess(); + void setFPPreciseEnabled(bool Value) { + setAllowFPReassociateOverride(!Value); + setNoHonorNaNsOverride(!Value); + setNoHonorInfsOverride(!Value); + setNoSignedZeroOverride(!Value); + setAllowReciprocalOverride(!Value); + setAllowApproxFuncOverride(!Value); + if (Value) + /* Precise mode implies fp_contract=on and disables ffast-math */ + setAllowFPContractWithinStatement(); + else + /* Precise mode disabled sets fp_contract=fast and enables ffast-math */ + setAllowFPContractAcrossStatement(); } - /// Used to serialize this. unsigned getAsOpaqueInt() const { - return fp_contract | (fenv_access << 2) | (rounding << 3) | - (exceptions << 6) | (allow_reassoc << 8) | (no_nans << 9) | - (no_infs << 10) | (no_signed_zeros << 11) | - (allow_reciprocal << 12) | (approx_func << 13); + return Options.getAsOpaqueInt() << 16 | OverrideMask; } - - /// Used with getAsOpaqueInt() to manage the float_control pragma stack. void getFromOpaqueInt(unsigned I) { - fp_contract = (static_cast(I & 3)); - fenv_access = ((I >> 2) & 1); - rounding = static_cast(static_cast((I >> 3) & 7)); - exceptions = (static_cast((I >> 6) & 3)); - allow_reassoc = ((I >> 8) & 1); - no_nans = ((I >> 9) & 1); - no_infs = ((I >> 10) & 1); - no_signed_zeros = ((I >> 11) & 1); - allow_reciprocal = ((I >> 12) & 1); - approx_func = ((I >> 13) & 1); + OverrideMask = I & 0xffff; + Options.getFromOpaqueInt(I >> 16); } -private: - /// 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; - /// Allow reassociation transformations for floating-point instructions - /// across multiple statements. - unsigned allow_reassoc : 1; - /// No NaNs - Allow optimizations to assume the arguments and result - /// are not NaN. If an argument is a nan, or the result would be a nan, - /// it produces a :ref:`poison value ` instead. - unsigned no_nans : 1; - /// No Infs - Allow optimizations to assume the arguments and result - /// are not +/-Inf. If an argument is +/-Inf, or the result would be +/-Inf, - /// it produces a :ref:`poison value ` instead. - unsigned no_infs : 1; - /// No Signed Zeros - Allow optimizations to treat the sign of a zero - /// argument or result as insignificant. - unsigned no_signed_zeros : 1; - /// Allow Reciprocal - Allow optimizations to use the reciprocal - /// of an argument rather than perform division. - unsigned allow_reciprocal : 1; - /// Approximate functions - Allow substitution of approximate calculations - /// for functions (sin, log, sqrt, etc). - unsigned approx_func : 1; -}; + FPOptions applyOverrides(const LangOptions &LO) { + FPOptions Base(LO); + FPOptions result((Base.getAsOpaqueInt() & ~OverrideMask) | + (Options.getAsOpaqueInt() & OverrideMask)); + return result; + } -inline bool operator==(FPOptions LHS, FPOptions RHS) { - return LHS.getAsOpaqueInt() == RHS.getAsOpaqueInt(); -} -inline bool operator!=(FPOptions LHS, FPOptions RHS) { - return LHS.getAsOpaqueInt() != RHS.getAsOpaqueInt(); -} + bool operator==(FPOptionsOverride other) const { + return Options == other.Options && OverrideMask == other.OverrideMask; + } + bool operator!=(FPOptionsOverride other) const { return !(*this == other); } + +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + bool has##NAME##Override() const { \ + return OverrideMask & FPOptions::NAME##Mask; \ + } \ + unsigned get##NAME##Override() const { \ + assert(has##NAME##Override()); \ + return Options.get##NAME(); \ + } \ + void clear##NAME##Override() { \ + /* Clear the actual value so that we don't have spurious differences when \ + * testing equality. */ \ + Options.set##NAME(TYPE(0)); \ + OverrideMask &= ~FPOptions::NAME##Mask; \ + } \ + void set##NAME##Override(TYPE value) { \ + Options.set##NAME(value); \ + OverrideMask |= FPOptions::NAME##Mask; \ + } +#include "clang/Basic/FPOptions.def" + LLVM_DUMP_METHOD void dump(); +}; /// Describes the kind of translation unit being processed. enum TranslationUnitKind { diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -193,12 +193,12 @@ COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro") COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math") -COMPATIBLE_LANGOPT(AllowFPReassoc , 1, 0, "Permit Floating Point reassociation") -COMPATIBLE_LANGOPT(NoHonorNaNs , 1, 0, "Permit Floating Point optimization without regard to NaN") -COMPATIBLE_LANGOPT(NoHonorInfs , 1, 0, "Permit Floating Point optimization without regard to infinities") -COMPATIBLE_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros") -COMPATIBLE_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal") -COMPATIBLE_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation") +BENIGN_LANGOPT(AllowFPReassoc , 1, 0, "Permit Floating Point reassociation") +BENIGN_LANGOPT(NoHonorNaNs , 1, 0, "Permit Floating Point optimization without regard to NaN") +BENIGN_LANGOPT(NoHonorInfs , 1, 0, "Permit Floating Point optimization without regard to infinities") +BENIGN_LANGOPT(NoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros") +BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal") +BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation") BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars") @@ -271,9 +271,9 @@ LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants") LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") /// FP_CONTRACT mode (on/off/fast). -ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type") -ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type") -ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type") +BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type") +BENIGN_ENUM_LANGOPT(FPRoundingMode, RoundingMode, 3, RoundingMode::NearestTiesToEven, "FP Rounding Mode type") +BENIGN_ENUM_LANGOPT(FPExceptionMode, FPExceptionModeKind, 2, FPE_Ignore, "FP Exception Behavior Mode type") LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") 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 @@ -557,6 +557,15 @@ // This stack tracks the current state of Sema.CurFPFeatures. PragmaStack FpPragmaStack; + FPOptionsOverride CurFPFeatureOverrides() { + FPOptionsOverride result; + if (!FpPragmaStack.hasValue()) { + result = FPOptionsOverride(); + } else { + result = FPOptionsOverride(FpPragmaStack.CurrentValue); + } + return result; + } // RAII object to push / pop sentinel slots for all MS #pragma stacks. // Actions should be performed only if we enter / exit a C++ method body. @@ -1358,12 +1367,19 @@ /// statements. class FPFeaturesStateRAII { public: - FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.CurFPFeatures) {} - ~FPFeaturesStateRAII() { S.CurFPFeatures = OldFPFeaturesState; } + FPFeaturesStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.CurFPFeatures) { + OldOverrides = S.FpPragmaStack.CurrentValue; + } + ~FPFeaturesStateRAII() { + S.CurFPFeatures = OldFPFeaturesState; + S.FpPragmaStack.CurrentValue = OldOverrides; + } + unsigned getOverrides() { return OldOverrides; } private: Sema& S; FPOptions OldFPFeaturesState; + unsigned OldOverrides; }; void addImplicitTypedef(StringRef Name, QualType T); @@ -9606,10 +9622,10 @@ /// Are precise floating point semantics currently enabled? bool isPreciseFPEnabled() { - return !CurFPFeatures.allowAssociativeMath() && - !CurFPFeatures.noSignedZeros() && - !CurFPFeatures.allowReciprocalMath() && - !CurFPFeatures.allowApproximateFunctions(); + return !CurFPFeatures.getAllowFPReassociate() && + !CurFPFeatures.getNoSignedZero() && + !CurFPFeatures.getAllowReciprocal() && + !CurFPFeatures.getAllowApproxFunc(); } /// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control @@ -9652,21 +9668,21 @@ /// ActOnPragmaFPContract - Called on well formed /// \#pragma {STDC,OPENCL} FP_CONTRACT and /// \#pragma clang fp contract - void ActOnPragmaFPContract(LangOptions::FPModeKind FPC); + void ActOnPragmaFPContract(SourceLocation Loc, LangOptions::FPModeKind FPC); /// Called on well formed /// \#pragma clang fp reassociate - void ActOnPragmaFPReassociate(bool IsEnabled); + void ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled); /// ActOnPragmaFenvAccess - Called on well formed /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); /// Called to set rounding mode for floating point operations. - void setRoundingMode(llvm::RoundingMode); + void setRoundingMode(SourceLocation Loc, llvm::RoundingMode); /// Called to set exception behavior for floating point operations. - void setExceptionMode(LangOptions::FPExceptionModeKind); + void setExceptionMode(SourceLocation Loc, LangOptions::FPExceptionModeKind); /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -62,6 +62,7 @@ class CXXTemporary; class FileEntry; class FPOptions; +class FPOptionsOverride; class FunctionDecl; class HeaderSearch; class HeaderSearchOptions; @@ -506,7 +507,7 @@ bool IsModule); void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(const DeclContext *DC); - void WriteFPPragmaOptions(const FPOptions &Opts); + void WriteFPPragmaOptions(const FPOptionsOverride &Opts); void WriteOpenCLExtensions(Sema &SemaRef); void WriteOpenCLExtensionTypes(Sema &SemaRef); void WriteOpenCLExtensionDecls(Sema &SemaRef); diff --git a/clang/include/clang/module.modulemap b/clang/include/clang/module.modulemap --- a/clang/include/clang/module.modulemap +++ b/clang/include/clang/module.modulemap @@ -54,6 +54,7 @@ textual header "Basic/CodeGenOptions.def" textual header "Basic/DiagnosticOptions.def" textual header "Basic/Features.def" + textual header "Basic/FPOptions.def" textual header "Basic/MSP430Target.def" textual header "Basic/LangOptions.def" textual header "Basic/OpenCLExtensions.def" 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 @@ -6676,7 +6676,7 @@ return UnaryOperator::Create( Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(), - E->getFPFeatures(Importer.getFromContext().getLangOpts())); + E->getFPOptionsOverride()); } ExpectedStmt diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4468,7 +4468,7 @@ BinaryOperator::BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, - FPOptions FPFeatures) + FPOptionsOverride FPFeatures) : Expr(BinaryOperatorClass, ResTy, VK, OK) { BinaryOperatorBits.Opc = opc; assert(!isCompoundAssignmentOp() && @@ -4476,8 +4476,7 @@ BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - BinaryOperatorBits.HasFPFeatures = - FPFeatures.requiresTrailingStorage(Ctx.getLangOpts()); + BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); if (BinaryOperatorBits.HasFPFeatures) *getTrailingFPFeatures() = FPFeatures; setDependence(computeDependence(this)); @@ -4486,7 +4485,7 @@ BinaryOperator::BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, - FPOptions FPFeatures, bool dead2) + FPOptionsOverride FPFeatures, bool dead2) : Expr(CompoundAssignOperatorClass, ResTy, VK, OK) { BinaryOperatorBits.Opc = opc; assert(isCompoundAssignmentOp() && @@ -4494,8 +4493,7 @@ BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; - BinaryOperatorBits.HasFPFeatures = - FPFeatures.requiresTrailingStorage(Ctx.getLangOpts()); + BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); if (BinaryOperatorBits.HasFPFeatures) *getTrailingFPFeatures() = FPFeatures; setDependence(computeDependence(this)); @@ -4513,8 +4511,8 @@ Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, - FPOptions FPFeatures) { - bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C.getLangOpts()); + FPOptionsOverride FPFeatures) { + bool HasFPFeatures = FPFeatures.requiresTrailingStorage(); unsigned Extra = sizeOfTrailingObjects(HasFPFeatures); void *Mem = C.Allocate(sizeof(BinaryOperator) + Extra, alignof(BinaryOperator)); @@ -4530,11 +4528,13 @@ return new (Mem) CompoundAssignOperator(C, EmptyShell(), HasFPFeatures); } -CompoundAssignOperator *CompoundAssignOperator::Create( - const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, - ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, - FPOptions FPFeatures, QualType CompLHSType, QualType CompResultType) { - bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C.getLangOpts()); +CompoundAssignOperator * +CompoundAssignOperator::Create(const ASTContext &C, Expr *lhs, Expr *rhs, + Opcode opc, QualType ResTy, ExprValueKind VK, + ExprObjectKind OK, SourceLocation opLoc, + FPOptionsOverride FPFeatures, + QualType CompLHSType, QualType CompResultType) { + bool HasFPFeatures = FPFeatures.requiresTrailingStorage(); unsigned Extra = sizeOfTrailingObjects(HasFPFeatures); void *Mem = C.Allocate(sizeof(CompoundAssignOperator) + Extra, alignof(CompoundAssignOperator)); @@ -4545,7 +4545,7 @@ UnaryOperator *UnaryOperator::CreateEmpty(const ASTContext &C, bool hasFPFeatures) { - void *Mem = C.Allocate(totalSizeToAlloc(hasFPFeatures), + void *Mem = C.Allocate(totalSizeToAlloc(hasFPFeatures), alignof(UnaryOperator)); return new (Mem) UnaryOperator(hasFPFeatures, EmptyShell()); } @@ -4553,13 +4553,12 @@ UnaryOperator::UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow, - FPOptions FPFeatures) + FPOptionsOverride FPFeatures) : Expr(UnaryOperatorClass, type, VK, OK), Val(input) { UnaryOperatorBits.Opc = opc; UnaryOperatorBits.CanOverflow = CanOverflow; UnaryOperatorBits.Loc = l; - UnaryOperatorBits.HasFPFeatures = - FPFeatures.requiresTrailingStorage(Ctx.getLangOpts()); + UnaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); setDependence(computeDependence(this)); } @@ -4567,9 +4566,9 @@ Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow, - FPOptions FPFeatures) { - bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C.getLangOpts()); - unsigned Size = totalSizeToAlloc(HasFPFeatures); + FPOptionsOverride FPFeatures) { + bool HasFPFeatures = FPFeatures.requiresTrailingStorage(); + unsigned Size = totalSizeToAlloc(HasFPFeatures); void *Mem = C.Allocate(Size, alignof(UnaryOperator)); return new (Mem) UnaryOperator(C, input, opc, type, VK, OK, l, CanOverflow, FPFeatures); diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -525,27 +525,27 @@ Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation OperatorLoc, - FPOptions FPFeatures, + FPOptionsOverride FPFeatures, ADLCallKind UsesADL) : CallExpr(CXXOperatorCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, OperatorLoc, /*MinNumArgs=*/0, UsesADL) { CXXOperatorCallExprBits.OperatorKind = OpKind; - CXXOperatorCallExprBits.FPFeatures = FPFeatures.getAsOpaqueInt(); assert( (CXXOperatorCallExprBits.OperatorKind == static_cast(OpKind)) && "OperatorKind overflow!"); - assert((CXXOperatorCallExprBits.FPFeatures == FPFeatures.getAsOpaqueInt()) && - "FPFeatures overflow!"); Range = getSourceRangeImpl(); + Overrides = FPFeatures; } CXXOperatorCallExpr::CXXOperatorCallExpr(unsigned NumArgs, EmptyShell Empty) : CallExpr(CXXOperatorCallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {} -CXXOperatorCallExpr *CXXOperatorCallExpr::Create( - const ASTContext &Ctx, OverloadedOperatorKind OpKind, Expr *Fn, - ArrayRef Args, QualType Ty, ExprValueKind VK, - SourceLocation OperatorLoc, FPOptions FPFeatures, ADLCallKind UsesADL) { +CXXOperatorCallExpr * +CXXOperatorCallExpr::Create(const ASTContext &Ctx, + OverloadedOperatorKind OpKind, Expr *Fn, + ArrayRef Args, QualType Ty, + ExprValueKind VK, SourceLocation OperatorLoc, + FPOptionsOverride FPFeatures, ADLCallKind UsesADL) { // Allocate storage for the trailing objects of CallExpr. unsigned NumArgs = Args.size(); unsigned SizeOfTrailingObjects = 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 @@ -116,18 +116,17 @@ QualType Ty) { return BinaryOperator::Create( C, const_cast(LHS), const_cast(RHS), BO_Assign, Ty, - VK_RValue, OK_Ordinary, SourceLocation(), FPOptions(C.getLangOpts())); + VK_RValue, OK_Ordinary, SourceLocation(), FPOptionsOverride()); } BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, BinaryOperator::Opcode Op) { assert(BinaryOperator::isLogicalOp(Op) || BinaryOperator::isComparisonOp(Op)); - return BinaryOperator::Create(C, const_cast(LHS), - const_cast(RHS), Op, - C.getLogicalOperationType(), VK_RValue, - OK_Ordinary, SourceLocation(), - FPOptions(C.getLangOpts())); + return BinaryOperator::Create( + C, const_cast(LHS), const_cast(RHS), Op, + C.getLogicalOperationType(), VK_RValue, OK_Ordinary, SourceLocation(), + FPOptionsOverride()); } CompoundStmt *ASTMaker::makeCompound(ArrayRef Stmts) { @@ -148,8 +147,7 @@ UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { return UnaryOperator::Create(C, const_cast(Arg), UO_Deref, Ty, VK_LValue, OK_Ordinary, SourceLocation(), - /*CanOverflow*/ false, - FPOptions(C.getLangOpts())); + /*CanOverflow*/ false, FPOptionsOverride()); } ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { @@ -297,7 +295,7 @@ /*QualType=*/C.VoidTy, /*ExprValueType=*/VK_RValue, /*SourceLocation=*/SourceLocation(), - /*FPFeatures=*/FPOptions(C.getLangOpts())); + /*FPFeatures=*/FPOptionsOverride()); } /// Create a fake body for std::call_once. @@ -457,7 +455,7 @@ /* QualType=*/C.IntTy, /* ExprValueKind=*/VK_RValue, /* ExprObjectKind=*/OK_Ordinary, SourceLocation(), - /* CanOverflow*/ false, FPOptions(C.getLangOpts())); + /* CanOverflow*/ false, FPOptionsOverride()); // Create assignment. BinaryOperator *FlagAssignment = M.makeAssignment( @@ -522,7 +520,7 @@ Expr *DoneValue = UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(), - /*CanOverflow*/ false, FPOptions(C.getLangOpts())); + /*CanOverflow*/ false, FPOptionsOverride()); BinaryOperator *B = M.makeAssignment( 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 @@ -24,7 +24,7 @@ #define LANGOPT(Name, Bits, Default, Description) #define BENIGN_LANGOPT(Name, Bits, Default, Description) Name = Default; #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - Name = Default; + Name = static_cast(Default); #include "clang/Basic/LangOptions.def" // These options do not affect AST generation. @@ -53,6 +53,17 @@ return result; } -bool FPOptions::requiresTrailingStorage(const LangOptions &LO) { - return getAsOpaqueInt() != defaultWithoutTrailingStorage(LO).getAsOpaqueInt(); +LLVM_DUMP_METHOD void FPOptions::dump() { +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + llvm::errs() << "\n " #NAME " " << get##NAME(); +#include "clang/Basic/FPOptions.def" + llvm::errs() << "\n"; +} + +LLVM_DUMP_METHOD void FPOptionsOverride::dump() { +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + if (has##NAME##Override()) \ + llvm::errs() << "\n " #NAME " Override is " << get##NAME##Override(); +#include "clang/Basic/FPOptions.def" + llvm::errs() << "\n"; } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2389,7 +2389,7 @@ if (!E->canOverflow()) return Builder.CreateNSWAdd(InVal, Amount, Name); return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec( - E, InVal, IsInc, E->getFPFeatures(CGF.getLangOpts()))); + E, InVal, IsInc, E->getFPFeaturesInEffect(CGF.getLangOpts()))); } llvm_unreachable("Unknown SignedOverflowBehaviorTy"); } @@ -2536,7 +2536,7 @@ } else if (E->canOverflow() && type->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) { value = EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec( - E, value, isInc, E->getFPFeatures(CGF.getLangOpts()))); + E, value, isInc, E->getFPFeaturesInEffect(CGF.getLangOpts()))); } else { llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); @@ -2736,7 +2736,7 @@ BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType()); BinOp.Ty = E->getType(); BinOp.Opcode = BO_Sub; - BinOp.FPFeatures = E->getFPFeatures(CGF.getLangOpts()); + BinOp.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts()); BinOp.E = E; return EmitSub(BinOp); } @@ -2757,7 +2757,7 @@ Value *Result; if (Oper->getType()->isFPOrFPVectorTy()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII( - CGF, E->getFPFeatures(CGF.getLangOpts())); + CGF, E->getFPFeaturesInEffect(CGF.getLangOpts())); Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp"); } else Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp"); @@ -2960,7 +2960,7 @@ Result.RHS = Visit(E->getRHS()); Result.Ty = E->getType(); Result.Opcode = E->getOpcode(); - Result.FPFeatures = E->getFPFeatures(CGF.getLangOpts()); + Result.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts()); Result.E = E; return Result; } @@ -2980,7 +2980,7 @@ OpInfo.RHS = Visit(E->getRHS()); OpInfo.Ty = E->getComputationResultType(); OpInfo.Opcode = E->getOpcode(); - OpInfo.FPFeatures = E->getFPFeatures(CGF.getLangOpts()); + OpInfo.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts()); OpInfo.E = E; // Load/convert the LHS. LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); @@ -4214,7 +4214,7 @@ Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); if (LHS->getType()->isFPOrFPVectorTy()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII( - CGF, E->getFPFeatures(CGF.getLangOpts())); + CGF, E->getFPFeaturesInEffect(CGF.getLangOpts())); LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); } else { @@ -4300,7 +4300,7 @@ Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); if (LHS->getType()->isFPOrFPVectorTy()) { CodeGenFunction::CGFPOptionsRAII FPOptsRAII( - CGF, E->getFPFeatures(CGF.getLangOpts())); + CGF, E->getFPFeaturesInEffect(CGF.getLangOpts())); LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); } else { diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1493,8 +1493,7 @@ BinaryOperator *assign = BinaryOperator::Create( getContext(), &ivarRef, finalArg, BO_Assign, ivarRef.getType(), VK_RValue, - OK_Ordinary, SourceLocation(), - FPOptions(getContext().getLangOpts())); + OK_Ordinary, SourceLocation(), FPOptionsOverride()); EmitStmt(assign); } @@ -3556,18 +3555,18 @@ DeclRefExpr DstExpr(C, &DstDecl, false, DestTy, VK_RValue, SourceLocation()); UnaryOperator *DST = UnaryOperator::Create( C, &DstExpr, UO_Deref, DestTy->getPointeeType(), VK_LValue, OK_Ordinary, - SourceLocation(), false, FPOptions(C.getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); DeclRefExpr SrcExpr(C, &SrcDecl, false, SrcTy, VK_RValue, SourceLocation()); UnaryOperator *SRC = UnaryOperator::Create( C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary, - SourceLocation(), false, FPOptions(C.getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); Expr *Args[2] = {DST, SRC}; CallExpr *CalleeExp = cast(PID->getSetterCXXAssignment()); CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(), - VK_LValue, SourceLocation(), FPOptions(C.getLangOpts())); + VK_LValue, SourceLocation(), FPOptionsOverride()); EmitStmt(TheCall); @@ -3641,7 +3640,7 @@ UnaryOperator *SRC = UnaryOperator::Create( C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary, - SourceLocation(), false, FPOptions(C.getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); CXXConstructExpr *CXXConstExpr = cast(PID->getGetterCXXConstructor()); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -3328,11 +3328,11 @@ // Generate condition for loop. BinaryOperator *Cond = BinaryOperator::Create( C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary, - S.getBeginLoc(), FPOptions(C.getLangOpts())); + S.getBeginLoc(), FPOptionsOverride()); // Increment for loop counter. UnaryOperator *Inc = UnaryOperator::Create( C, &IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, - S.getBeginLoc(), true, FPOptions(C.getLangOpts())); + S.getBeginLoc(), true, FPOptionsOverride()); auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) { // Iterate through all sections and emit a switch construct: // switch (IV) { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -117,12 +117,12 @@ void CodeGenFunction::SetFastMathFlags(FPOptions FPFeatures) { llvm::FastMathFlags FMF; - FMF.setAllowReassoc(FPFeatures.allowAssociativeMath()); - FMF.setNoNaNs(FPFeatures.noHonorNaNs()); - FMF.setNoInfs(FPFeatures.noHonorInfs()); - FMF.setNoSignedZeros(FPFeatures.noSignedZeros()); - FMF.setAllowReciprocal(FPFeatures.allowReciprocalMath()); - FMF.setApproxFunc(FPFeatures.allowApproximateFunctions()); + FMF.setAllowReassoc(FPFeatures.getAllowFPReassociate()); + FMF.setNoNaNs(FPFeatures.getNoHonorNaNs()); + FMF.setNoInfs(FPFeatures.getNoHonorInfs()); + FMF.setNoSignedZeros(FPFeatures.getNoSignedZero()); + FMF.setAllowReciprocal(FPFeatures.getAllowReciprocal()); + FMF.setApproxFunc(FPFeatures.getAllowApproxFunc()); FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement()); Builder.setFastMathFlags(FMF); } @@ -137,10 +137,12 @@ FMFGuard.emplace(CGF.Builder); - auto NewRoundingBehavior = FPFeatures.getRoundingMode(); + llvm::RoundingMode NewRoundingBehavior = + static_cast(FPFeatures.getRoundingMode()); CGF.Builder.setDefaultConstrainedRounding(NewRoundingBehavior); auto NewExceptionBehavior = - ToConstrainedExceptMD(FPFeatures.getExceptionMode()); + ToConstrainedExceptMD(static_cast( + FPFeatures.getFPExceptionMode())); CGF.Builder.setDefaultConstrainedExcept(NewExceptionBehavior); CGF.SetFastMathFlags(FPFeatures); @@ -159,13 +161,13 @@ if (OldValue != NewValue) CGF.CurFn->addFnAttr(Name, llvm::toStringRef(NewValue)); }; - mergeFnAttrValue("no-infs-fp-math", FPFeatures.noHonorInfs()); - mergeFnAttrValue("no-nans-fp-math", FPFeatures.noHonorNaNs()); - mergeFnAttrValue("no-signed-zeros-fp-math", FPFeatures.noSignedZeros()); - mergeFnAttrValue( - "unsafe-fp-math", - FPFeatures.allowAssociativeMath() && FPFeatures.allowReciprocalMath() && - FPFeatures.allowApproximateFunctions() && FPFeatures.noSignedZeros()); + mergeFnAttrValue("no-infs-fp-math", FPFeatures.getNoHonorInfs()); + mergeFnAttrValue("no-nans-fp-math", FPFeatures.getNoHonorNaNs()); + mergeFnAttrValue("no-signed-zeros-fp-math", FPFeatures.getNoSignedZero()); + mergeFnAttrValue("unsafe-fp-math", FPFeatures.getAllowFPReassociate() && + FPFeatures.getAllowReciprocal() && + FPFeatures.getAllowApproxFunc() && + FPFeatures.getNoSignedZero()); } CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() { diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -2590,7 +2590,7 @@ Expr *Unop = UnaryOperator::Create( const_cast(*Context), DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CK_CPointerToObjCPointerCast, Unop); @@ -3287,7 +3287,7 @@ SuperRep = UnaryOperator::Create( const_cast(*Context), SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -3305,7 +3305,7 @@ SuperRep = UnaryOperator::Create( const_cast(*Context), SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); } MsgExprs.push_back(SuperRep); break; @@ -3382,7 +3382,7 @@ SuperRep = UnaryOperator::Create( const_cast(*Context), SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -4706,10 +4706,9 @@ if (VarDecl *Var = dyn_cast(VD)) if (!ImportedLocalExternalDecls.count(Var)) return DRE; - Expr *Exp = UnaryOperator::Create(const_cast(*Context), DRE, - UO_Deref, DRE->getType(), VK_LValue, - OK_Ordinary, DRE->getLocation(), false, - FPOptions(Context->getLangOpts())); + Expr *Exp = UnaryOperator::Create( + const_cast(*Context), DRE, UO_Deref, DRE->getType(), + VK_LValue, OK_Ordinary, DRE->getLocation(), false, FPOptionsOverride()); // Need parens to enforce precedence. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), Exp); @@ -5300,7 +5299,7 @@ new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy, VK_LValue, SourceLocation()), UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue, - OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts())); + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); InitExprs.push_back(DescRefExpr); // Add initializers for any closure decl refs. @@ -5317,10 +5316,9 @@ if (HasLocalVariableExternalStorage(*I)) { QualType QT = (*I)->getType(); QT = Context->getPointerType(QT); - Exp = UnaryOperator::Create(const_cast(*Context), Exp, - UO_AddrOf, QT, VK_RValue, OK_Ordinary, - SourceLocation(), false, - FPOptions(Context->getLangOpts())); + Exp = UnaryOperator::Create( + const_cast(*Context), Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); } } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getName()); @@ -5335,10 +5333,9 @@ if (HasLocalVariableExternalStorage(*I)) { QualType QT = (*I)->getType(); QT = Context->getPointerType(QT); - Exp = UnaryOperator::Create(const_cast(*Context), Exp, - UO_AddrOf, QT, VK_RValue, OK_Ordinary, - SourceLocation(), false, - FPOptions(Context->getLangOpts())); + Exp = UnaryOperator::Create( + const_cast(*Context), Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); } } @@ -5379,7 +5376,7 @@ Exp = UnaryOperator::Create( const_cast(*Context), Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); InitExprs.push_back(Exp); } @@ -5406,7 +5403,7 @@ NewRep = UnaryOperator::Create( const_cast(*Context), NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep); // Put Paren around the call. @@ -7494,7 +7491,7 @@ BinaryOperator *addExpr = BinaryOperator::Create( *Context, castExpr, DRE, BO_Add, Context->getPointerType(Context->CharTy), VK_RValue, OK_Ordinary, - SourceLocation(), FPOptions(Context->getLangOpts())); + SourceLocation(), FPOptionsOverride()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), @@ -7545,10 +7542,9 @@ CK_BitCast, PE); - Expr *Exp = UnaryOperator::Create(const_cast(*Context), - castExpr, UO_Deref, IvarT, VK_LValue, - OK_Ordinary, SourceLocation(), false, - FPOptions(Context->getLangOpts())); + Expr *Exp = UnaryOperator::Create( + const_cast(*Context), castExpr, UO_Deref, IvarT, + VK_LValue, OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); PE = new (Context) ParenExpr(OldRange.getBegin(), OldRange.getEnd(), Exp); diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -2517,7 +2517,7 @@ Expr *Unop = UnaryOperator::Create( const_cast(*Context), DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), CK_CPointerToObjCPointerCast, Unop); @@ -2718,7 +2718,7 @@ SuperRep = UnaryOperator::Create( const_cast(*Context), SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -2736,7 +2736,7 @@ SuperRep = UnaryOperator::Create( const_cast(*Context), SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); } MsgExprs.push_back(SuperRep); break; @@ -2813,7 +2813,7 @@ SuperRep = UnaryOperator::Create( const_cast(*Context), SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), CK_BitCast, SuperRep); @@ -2999,7 +2999,7 @@ SourceLocation()); BinaryOperator *lessThanExpr = BinaryOperator::Create( *Context, sizeofExpr, limit, BO_LE, Context->IntTy, VK_RValue, - OK_Ordinary, SourceLocation(), FPOptions(Context->getLangOpts())); + OK_Ordinary, SourceLocation(), FPOptionsOverride()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) ConditionalOperator *CondExpr = new (Context) ConditionalOperator(lessThanExpr, @@ -3052,7 +3052,7 @@ Expr *DerefExpr = UnaryOperator::Create( const_cast(*Context), DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), CK_BitCast, DerefExpr); @@ -3877,10 +3877,9 @@ if (VarDecl *Var = dyn_cast(VD)) if (!ImportedLocalExternalDecls.count(Var)) return DRE; - Expr *Exp = UnaryOperator::Create(const_cast(*Context), DRE, - UO_Deref, DRE->getType(), VK_LValue, - OK_Ordinary, DRE->getLocation(), false, - FPOptions(Context->getLangOpts())); + Expr *Exp = UnaryOperator::Create( + const_cast(*Context), DRE, UO_Deref, DRE->getType(), + VK_LValue, OK_Ordinary, DRE->getLocation(), false, FPOptionsOverride()); // Need parens to enforce precedence. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), Exp); @@ -4440,7 +4439,7 @@ new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy, VK_LValue, SourceLocation()), UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue, - OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts())); + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); InitExprs.push_back(DescRefExpr); // Add initializers for any closure decl refs. @@ -4457,10 +4456,9 @@ if (HasLocalVariableExternalStorage(*I)) { QualType QT = (*I)->getType(); QT = Context->getPointerType(QT); - Exp = UnaryOperator::Create(const_cast(*Context), Exp, - UO_AddrOf, QT, VK_RValue, OK_Ordinary, - SourceLocation(), false, - FPOptions(Context->getLangOpts())); + Exp = UnaryOperator::Create( + const_cast(*Context), Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); } } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getName()); @@ -4475,10 +4473,9 @@ if (HasLocalVariableExternalStorage(*I)) { QualType QT = (*I)->getType(); QT = Context->getPointerType(QT); - Exp = UnaryOperator::Create(const_cast(*Context), Exp, - UO_AddrOf, QT, VK_RValue, OK_Ordinary, - SourceLocation(), false, - FPOptions(Context->getLangOpts())); + Exp = UnaryOperator::Create( + const_cast(*Context), Exp, UO_AddrOf, QT, VK_RValue, + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); } } InitExprs.push_back(Exp); @@ -4518,7 +4515,7 @@ Exp = UnaryOperator::Create( const_cast(*Context), Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp); InitExprs.push_back(Exp); } @@ -4537,7 +4534,7 @@ NewRep = UnaryOperator::Create( const_cast(*Context), NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary, - SourceLocation(), false, FPOptions(Context->getLangOpts())); + SourceLocation(), false, FPOptionsOverride()); NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast, NewRep); BlockDeclRefs.clear(); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3371,8 +3371,10 @@ // to the levels specified on the command line. Previous level // will be restored when the RAII object is destroyed. Sema::FPFeaturesStateRAII SaveFPFeaturesState(Actions); - FPOptions fpOptions(getLangOpts()); - Actions.CurFPFeatures.getFromOpaqueInt(fpOptions.getAsOpaqueInt()); + FPOptionsOverride NewOverrides; + Actions.CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); + Actions.FpPragmaStack.Act(Tok.getLocation(), Sema::PSK_Reset, StringRef(), + 0 /*unused*/); SourceLocation SavedPrevTokLocation = PrevTokLocation; ParseLexedPragmas(getCurrentClass()); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -654,8 +654,8 @@ break; } - Actions.ActOnPragmaFPContract(FPC); - ConsumeAnnotationToken(); + SourceLocation PragmaLoc = ConsumeAnnotationToken(); + Actions.ActOnPragmaFPContract(PragmaLoc, FPC); } void Parser::HandlePragmaFloatControl() { @@ -2935,8 +2935,8 @@ reinterpret_cast(Tok.getAnnotationValue()); if (AnnotValue->FlagKind == TokFPAnnotValue::Reassociate) - Actions.ActOnPragmaFPReassociate(AnnotValue->FlagValue == - TokFPAnnotValue::On); + Actions.ActOnPragmaFPReassociate( + Tok.getLocation(), AnnotValue->FlagValue == TokFPAnnotValue::On); else { LangOptions::FPModeKind FPC; switch (AnnotValue->FlagValue) { @@ -2950,7 +2950,7 @@ FPC = LangOptions::FPM_Fast; break; } - Actions.ActOnPragmaFPContract(FPC); + Actions.ActOnPragmaFPContract(Tok.getLocation(), FPC); } ConsumeAnnotationToken(); } 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 @@ -159,9 +159,8 @@ LangOpts.getMSPointerToMemberRepresentationMethod()), VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), - CodeSegStack(nullptr), FpPragmaStack(CurFPFeatures.getAsOpaqueInt()), - CurInitSeg(nullptr), VisContext(nullptr), - PragmaAttributeCurrentTargetDecl(nullptr), + CodeSegStack(nullptr), FpPragmaStack(0xffffffff), CurInitSeg(nullptr), + VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), 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 @@ -417,8 +417,10 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action, PragmaFloatControlKind Value) { - auto NewValue = FpPragmaStack.CurrentValue; - FPOptions NewFPFeatures(NewValue); + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) && !(CurContext->isTranslationUnit()) && !CurContext->isNamespace()) { // Push and pop can only occur at file or namespace scope. @@ -429,38 +431,34 @@ default: llvm_unreachable("invalid pragma float_control kind"); case PFC_Precise: - CurFPFeatures.setFPPreciseEnabled(true); - NewValue = CurFPFeatures.getAsOpaqueInt(); + NewFPFeatures.setFPPreciseEnabled(true); + NewValue = NewFPFeatures.getAsOpaqueInt(); FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); break; case PFC_NoPrecise: - if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict) + if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict) Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept); - else if (CurFPFeatures.allowFEnvAccess()) + else if (CurFPFeatures.getAllowFEnvAccess()) Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv); else - CurFPFeatures.setFPPreciseEnabled(false); - NewValue = CurFPFeatures.getAsOpaqueInt(); + NewFPFeatures.setFPPreciseEnabled(false); + NewValue = NewFPFeatures.getAsOpaqueInt(); FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); break; case PFC_Except: if (!isPreciseFPEnabled()) Diag(Loc, diag::err_pragma_fc_except_requires_precise); else - CurFPFeatures.setExceptionMode(LangOptions::FPE_Strict); - NewValue = CurFPFeatures.getAsOpaqueInt(); + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); + NewValue = NewFPFeatures.getAsOpaqueInt(); FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); break; case PFC_NoExcept: - CurFPFeatures.setExceptionMode(LangOptions::FPE_Ignore); - NewValue = CurFPFeatures.getAsOpaqueInt(); + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore); + NewValue = NewFPFeatures.getAsOpaqueInt(); FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); break; case PFC_Push: - if (FpPragmaStack.Stack.empty()) { - FpPragmaStack.Act(Loc, Sema::PSK_Set, StringRef(), - CurFPFeatures.getAsOpaqueInt()); - } FpPragmaStack.Act(Loc, Sema::PSK_Push_Set, StringRef(), NewFPFeatures.getAsOpaqueInt()); break; @@ -472,9 +470,12 @@ } FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt()); NewValue = FpPragmaStack.CurrentValue; - CurFPFeatures.getFromOpaqueInt(NewValue); break; } + FPOptionsOverride NewOverrides; + if (NewValue != FpPragmaStack.DefaultValue) + NewOverrides.getFromOpaqueInt(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); } void Sema::ActOnPragmaMSPointersToMembers( @@ -1003,33 +1004,70 @@ } } -void Sema::ActOnPragmaFPContract(LangOptions::FPModeKind FPC) { +void Sema::ActOnPragmaFPContract(SourceLocation Loc, + LangOptions::FPModeKind FPC) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); switch (FPC) { case LangOptions::FPM_On: - CurFPFeatures.setAllowFPContractWithinStatement(); + NewFPFeatures.setAllowFPContractWithinStatement(); break; case LangOptions::FPM_Fast: - CurFPFeatures.setAllowFPContractAcrossStatement(); + NewFPFeatures.setAllowFPContractAcrossStatement(); break; case LangOptions::FPM_Off: - CurFPFeatures.setDisallowFPContract(); + NewFPFeatures.setDisallowFPContract(); break; } + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + FpPragmaStack.Act(Loc, Sema::PSK_Set, StringRef(), + NewFPFeatures.getAsOpaqueInt()); } -void Sema::ActOnPragmaFPReassociate(bool IsEnabled) { - CurFPFeatures.setAllowAssociativeMath(IsEnabled); +void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + NewFPFeatures.setAllowFPReassociateOverride(IsEnabled); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); } -void Sema::setRoundingMode(llvm::RoundingMode FPR) { - CurFPFeatures.setRoundingMode(FPR); +void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + NewFPFeatures.setRoundingModeOverride(FPR); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); } -void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) { - CurFPFeatures.setExceptionMode(FPE); +void Sema::setExceptionMode(SourceLocation Loc, + LangOptions::FPExceptionModeKind FPE) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + NewFPFeatures.setFPExceptionModeOverride(FPE); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); } void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); if (IsEnabled) { // Verify Microsoft restriction: // You can't enable fenv_access unless precise semantics are enabled. @@ -1037,9 +1075,13 @@ // pragma, or by using the /fp:precise or /fp:strict compiler options if (!isPreciseFPEnabled()) Diag(Loc, diag::err_pragma_fenv_requires_precise); - CurFPFeatures.setAllowFEnvAccess(); + NewFPFeatures.setAllowFEnvAccessOverride(true); } else - CurFPFeatures.setDisallowFEnvAccess(); + NewFPFeatures.setAllowFEnvAccessOverride(false); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); } void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, 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 @@ -13526,11 +13526,11 @@ Expr *From = FromB.build(S, Loc); From = UnaryOperator::Create( S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()), - VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatures); + VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); Expr *To = ToB.build(S, Loc); - To = UnaryOperator::Create(S.Context, To, UO_AddrOf, - S.Context.getPointerType(To->getType()), VK_RValue, - OK_Ordinary, Loc, false, S.CurFPFeatures); + To = UnaryOperator::Create( + S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()), + VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = @@ -13767,14 +13767,14 @@ Expr *Comparison = BinaryOperator::Create( S.Context, IterationVarRefRVal.build(S, Loc), IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE, - S.Context.BoolTy, VK_RValue, OK_Ordinary, Loc, S.CurFPFeatures); + S.Context.BoolTy, VK_RValue, OK_Ordinary, Loc, S.CurFPFeatureOverrides()); // Create the pre-increment of the iteration variable. We can determine // whether the increment will overflow based on the value of the array // bound. Expr *Increment = UnaryOperator::Create( S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue, - OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatures); + OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatureOverrides()); // Construct the loop that copies all elements of this array. return S.ActOnForStmt( diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13630,7 +13630,7 @@ BinaryOperatorKind Opc, QualType ResultTy, ExprValueKind VK, ExprObjectKind OK, bool IsCompAssign, SourceLocation OpLoc, - FPOptions FPFeatures) { + FPOptionsOverride FPFeatures) { auto &Context = S.getASTContext(); assert((isVector(ResultTy, Context.HalfTy) || isVector(ResultTy, Context.ShortTy)) && @@ -13953,9 +13953,9 @@ if (CompResultTy.isNull()) { if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, - OpLoc, CurFPFeatures); + OpLoc, CurFPFeatureOverrides()); return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy, - VK, OK, OpLoc, CurFPFeatures); + VK, OK, OpLoc, CurFPFeatureOverrides()); } // Handle compound assignments. @@ -13973,11 +13973,11 @@ if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, - OpLoc, CurFPFeatures); + OpLoc, CurFPFeatureOverrides()); - return CompoundAssignOperator::Create(Context, LHS.get(), RHS.get(), Opc, - ResultTy, VK, OK, OpLoc, CurFPFeatures, - CompLHSTy, CompResultTy); + return CompoundAssignOperator::Create( + Context, LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, + CurFPFeatureOverrides(), CompLHSTy, CompResultTy); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -14565,8 +14565,9 @@ if (Opc != UO_AddrOf && Opc != UO_Deref) CheckArrayAccess(Input.get()); - auto *UO = UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK, - OK, OpLoc, CanOverflow, CurFPFeatures); + auto *UO = + UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK, OK, + OpLoc, CanOverflow, CurFPFeatureOverrides()); if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) && !isa(UO->getType().getDesugaredType(Context))) diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -4487,7 +4487,8 @@ Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(), sub->getValueKind(), sub->getObjectKind(), - uo->getOperatorLoc(), false, CurFPFeatures); + uo->getOperatorLoc(), false, + CurFPFeatureOverrides()); } else if (GenericSelectionExpr *gse = dyn_cast(e)) { assert(!gse->isResultDependent()); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -13041,7 +13041,7 @@ if (Fns.empty()) return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, VK_RValue, OK_Ordinary, OpLoc, false, - CurFPFeatures); + CurFPFeatureOverrides()); CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create( @@ -13049,7 +13049,7 @@ /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return CXXOperatorCallExpr::Create(Context, Op, Fn, ArgsArray, Context.DependentTy, VK_RValue, OpLoc, - CurFPFeatures); + CurFPFeatureOverrides()); } // Build an empty overload set. @@ -13123,7 +13123,7 @@ Args[0] = Input; CallExpr *TheCall = CXXOperatorCallExpr::Create( Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc, - CurFPFeatures, Best->IsADLCandidate); + CurFPFeatureOverrides(), Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -13292,12 +13292,12 @@ // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BO_Assign || Opc > BO_OrAssign) - return BinaryOperator::Create(Context, Args[0], Args[1], Opc, - Context.DependentTy, VK_RValue, - OK_Ordinary, OpLoc, CurFPFeatures); + return BinaryOperator::Create( + Context, Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, + OK_Ordinary, OpLoc, CurFPFeatureOverrides()); return CompoundAssignOperator::Create( Context, Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, - OK_Ordinary, OpLoc, CurFPFeatures, Context.DependentTy, + OK_Ordinary, OpLoc, CurFPFeatureOverrides(), Context.DependentTy, Context.DependentTy); } @@ -13311,7 +13311,7 @@ /*ADL*/ PerformADL, IsOverloaded(Fns), Fns.begin(), Fns.end()); return CXXOperatorCallExpr::Create(Context, Op, Fn, Args, Context.DependentTy, VK_RValue, OpLoc, - CurFPFeatures); + CurFPFeatureOverrides()); } // Always do placeholder-like conversions on the RHS. @@ -13480,7 +13480,7 @@ CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc, - CurFPFeatures, Best->IsADLCandidate); + CurFPFeatureOverrides(), Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) @@ -13748,7 +13748,7 @@ Expr *SyntacticForm = BinaryOperator::Create( Context, OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(), Result.get()->getValueKind(), Result.get()->getObjectKind(), OpLoc, - CurFPFeatures); + CurFPFeatureOverrides()); Expr *SemanticForm[] = {LHS, RHS, Result.get()}; return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2); } @@ -13779,7 +13779,7 @@ return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn, Args, Context.DependentTy, VK_RValue, RLoc, - CurFPFeatures); + CurFPFeatureOverrides()); } // Handle placeholders on both operands. @@ -13852,9 +13852,9 @@ ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = - CXXOperatorCallExpr::Create(Context, OO_Subscript, FnExpr.get(), - Args, ResultTy, VK, RLoc, CurFPFeatures); + CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( + Context, OO_Subscript, FnExpr.get(), Args, ResultTy, VK, RLoc, + CurFPFeatureOverrides()); if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl)) return ExprError(); @@ -14476,9 +14476,9 @@ ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = - CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(), MethodArgs, - ResultTy, VK, RParenLoc, CurFPFeatures); + CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( + Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc, + CurFPFeatureOverrides()); if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method)) return true; @@ -14594,8 +14594,9 @@ QualType ResultTy = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, CurFPFeatures); + CXXOperatorCallExpr *TheCall = + CXXOperatorCallExpr::Create(Context, OO_Arrow, FnExpr.get(), Base, + ResultTy, VK, OpLoc, CurFPFeatureOverrides()); if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method)) return ExprError(); @@ -14844,7 +14845,7 @@ return UnaryOperator::Create( Context, SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc(), false, CurFPFeatures); + UnOp->getOperatorLoc(), false, CurFPFeatureOverrides()); } } Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), @@ -14852,9 +14853,10 @@ if (SubExpr == UnOp->getSubExpr()) return UnOp; - return UnaryOperator::Create( - Context, SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()), - VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(), false, CurFPFeatures); + return UnaryOperator::Create(Context, SubExpr, UO_AddrOf, + Context.getPointerType(SubExpr->getType()), + VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(), + false, CurFPFeatureOverrides()); } if (UnresolvedLookupExpr *ULE = dyn_cast(E)) { diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -130,7 +130,7 @@ return UnaryOperator::Create( S.Context, e, uop->getOpcode(), uop->getType(), uop->getValueKind(), uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(), - S.CurFPFeatures); + S.CurFPFeatureOverrides()); } if (GenericSelectionExpr *gse = dyn_cast(e)) { @@ -446,9 +446,10 @@ ExprResult result; if (opcode == BO_Assign) { result = semanticRHS; - syntactic = BinaryOperator::Create( - S.Context, syntacticLHS, capturedRHS, opcode, capturedRHS->getType(), - capturedRHS->getValueKind(), OK_Ordinary, opcLoc, S.CurFPFeatures); + syntactic = BinaryOperator::Create(S.Context, syntacticLHS, capturedRHS, + opcode, capturedRHS->getType(), + capturedRHS->getValueKind(), OK_Ordinary, + opcLoc, S.CurFPFeatureOverrides()); } else { ExprResult opLHS = buildGet(); @@ -462,8 +463,9 @@ syntactic = CompoundAssignOperator::Create( S.Context, syntacticLHS, capturedRHS, opcode, result.get()->getType(), - result.get()->getValueKind(), OK_Ordinary, opcLoc, S.CurFPFeatures, - opLHS.get()->getType(), result.get()->getType()); + result.get()->getValueKind(), OK_Ordinary, opcLoc, + S.CurFPFeatureOverrides(), opLHS.get()->getType(), + result.get()->getType()); } // The result of the assignment, if not void, is the value set into @@ -531,7 +533,7 @@ ? S.Context.getTypeSize(resultType) >= S.Context.getTypeSize(S.Context.IntTy) : false, - S.CurFPFeatures); + S.CurFPFeatureOverrides()); return complete(syntactic); } @@ -1553,7 +1555,7 @@ if (op->isTypeDependent()) return UnaryOperator::Create(Context, op, opcode, Context.DependentTy, VK_RValue, OK_Ordinary, opcLoc, false, - CurFPFeatures); + CurFPFeatureOverrides()); assert(UnaryOperator::isIncrementDecrementOp(opcode)); Expr *opaqueRef = op->IgnoreParens(); @@ -1584,7 +1586,7 @@ if (LHS->isTypeDependent() || RHS->isTypeDependent()) return BinaryOperator::Create(Context, LHS, RHS, opcode, Context.DependentTy, VK_RValue, OK_Ordinary, - opcLoc, CurFPFeatures); + opcLoc, CurFPFeatureOverrides()); // Filter out non-overload placeholder types in the RHS. if (RHS->getType()->isNonOverloadPlaceholderType()) { @@ -1640,7 +1642,7 @@ return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(), uop->getValueKind(), uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(), - CurFPFeatures); + CurFPFeatureOverrides()); } else if (CompoundAssignOperator *cop = dyn_cast(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); @@ -1648,7 +1650,7 @@ return CompoundAssignOperator::Create( Context, lhs, rhs, cop->getOpcode(), cop->getType(), cop->getValueKind(), cop->getObjectKind(), cop->getOperatorLoc(), - CurFPFeatures, cop->getComputationLHSType(), + CurFPFeatureOverrides(), cop->getComputationLHSType(), cop->getComputationResultType()); } else if (BinaryOperator *bop = dyn_cast(syntax)) { @@ -1657,7 +1659,7 @@ return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(), bop->getType(), bop->getValueKind(), bop->getObjectKind(), bop->getOperatorLoc(), - CurFPFeatures); + CurFPFeatureOverrides()); } else if (isa(syntax)) { return syntax; 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 @@ -10564,8 +10564,10 @@ return getDerived().RebuildBinaryOperator( E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); - getSema().CurFPFeatures = E->getFPFeatures(getSema().getLangOpts()); - + FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts())); + getSema().CurFPFeatures = + NewOverrides.applyOverrides(getSema().getLangOpts()); + getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt(); return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); } @@ -10619,7 +10621,10 @@ TreeTransform::TransformCompoundAssignOperator( CompoundAssignOperator *E) { Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); - getSema().CurFPFeatures = E->getFPFeatures(getSema().getLangOpts()); + FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts())); + getSema().CurFPFeatures = + NewOverrides.applyOverrides(getSema().getLangOpts()); + getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt(); return getDerived().TransformBinaryOperator(E); } @@ -11094,7 +11099,10 @@ return SemaRef.MaybeBindToTemporary(E); Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); - getSema().CurFPFeatures = E->getFPFeatures(); + FPOptionsOverride NewOverrides(E->getFPFeatures()); + getSema().CurFPFeatures = + NewOverrides.applyOverrides(getSema().getLangOpts()); + getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt(); return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), E->getOperatorLoc(), diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7843,7 +7843,9 @@ // FIXME: What happens if these are changed by a module import? if (!FPPragmaOptions.empty()) { assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); - SemaObj->CurFPFeatures = FPOptions(FPPragmaOptions[0]); + FPOptionsOverride NewOverrides(FPPragmaOptions[0]); + SemaObj->CurFPFeatures = + NewOverrides.applyOverrides(SemaObj->getLangOpts()); } SemaObj->OpenCLFeatures.copy(OpenCLExtensions); 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 @@ -706,7 +706,7 @@ E->setOperatorLoc(readSourceLocation()); E->setCanOverflow(Record.readInt()); if (hasFP_Features) - E->setStoredFPFeatures(FPOptions(Record.readInt())); + E->setStoredFPFeatures(FPOptionsOverride(Record.readInt())); } void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { @@ -1089,7 +1089,7 @@ E->setRHS(Record.readSubExpr()); E->setOperatorLoc(readSourceLocation()); if (hasFP_Features) - E->setStoredFPFeatures(FPOptions(Record.readInt())); + E->setStoredFPFeatures(FPOptionsOverride(Record.readInt())); } void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { @@ -1657,8 +1657,8 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); E->CXXOperatorCallExprBits.OperatorKind = Record.readInt(); - E->CXXOperatorCallExprBits.FPFeatures = Record.readInt(); E->Range = Record.readSourceRange(); + E->setFPFeatures(FPOptionsOverride(Record.readInt())); } void ASTStmtReader::VisitCXXRewrittenBinaryOperator( diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3960,7 +3960,7 @@ } /// Write an FP_PRAGMA_OPTIONS block for the given FPOptions. -void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { +void ASTWriter::WriteFPPragmaOptions(const FPOptionsOverride &Opts) { RecordData::value_type Record[] = {Opts.getAsOpaqueInt()}; Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); } @@ -4790,7 +4790,7 @@ WriteReferencedSelectorsPool(SemaRef); WriteLateParsedTemplates(SemaRef); WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); - WriteFPPragmaOptions(SemaRef.getCurFPFeatures()); + WriteFPPragmaOptions(SemaRef.CurFPFeatureOverrides()); WriteOpenCLExtensions(SemaRef); WriteOpenCLExtensionTypes(SemaRef); WriteCUDAPragmas(SemaRef); 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 @@ -1545,8 +1545,8 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); Record.push_back(E->getOperator()); - Record.push_back(E->getFPFeatures().getAsOpaqueInt()); Record.AddSourceRange(E->Range); + Record.push_back(E->getFPFeatures().getAsOpaqueInt()); Code = serialization::EXPR_CXX_OPERATOR_CALL; } diff --git a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp --- a/clang/test/CodeGen/fp-floatcontrol-pragma.cpp +++ b/clang/test/CodeGen/fp-floatcontrol-pragma.cpp @@ -119,6 +119,24 @@ return x; } +#pragma float_control(push) +#pragma float_control(precise, on) +struct Distance {}; +Distance operator+(Distance, Distance); + +template +T add(T lhs, T rhs) { +#pragma float_control(except, on) + return lhs + rhs; +} +#pragma float_control(pop) + +float test_OperatorCall() { + return add(1.0f, 2.0f); + //CHECK: llvm.experimental.constrained.fadd{{.*}}fpexcept.strict +} +// CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}} + #if FENV_ON // expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}} #pragma STDC FENV_ACCESS ON diff --git a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl --- a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl +++ b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl @@ -5,6 +5,17 @@ // RUN: %clang_cc1 %s -emit-llvm -cl-mad-enable -o - | FileCheck %s -check-prefix=MAD // RUN: %clang_cc1 %s -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSIGNED +// Check the fp options are correct with PCH. +// RUN: %clang_cc1 %s -DGEN_PCH=1 -finclude-default-header -triple spir-unknown-unknown -emit-pch -o %t.pch +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -o - | FileCheck %s -check-prefix=NORMAL +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-unsafe-math-optimizations -o - | FileCheck %s -check-prefix=UNSAFE +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-mad-enable -o - | FileCheck %s -check-prefix=MAD +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSIGNED + +#if !GEN_PCH + float spscalardiv(float a, float b) { // CHECK: @spscalardiv( @@ -53,3 +64,8 @@ // NOSIGNED: "no-nans-fp-math"="false" // NOSIGNED: "no-signed-zeros-fp-math"="true" // NOSIGNED: "unsafe-fp-math"="false" + +#else +// Undefine this to avoid putting it in the PCH. +#undef GEN_PCH +#endif diff --git a/clang/test/PCH/pragma-floatcontrol.c b/clang/test/PCH/pragma-floatcontrol.c --- a/clang/test/PCH/pragma-floatcontrol.c +++ b/clang/test/PCH/pragma-floatcontrol.c @@ -6,6 +6,18 @@ // Test with pch. // RUN: %clang_cc1 %s -DSET -emit-pch -o %t // RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s +// RUN: %clang_cc1 %s -ffp-contract=on -DSET -emit-pch -o %t +// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s +// RUN: %clang_cc1 %s -menable-no-nans -DSET -emit-pch -o %t +// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s +// RUN: %clang_cc1 %s -frounding-math -DSET -emit-pch -o %t +// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s +// RUN: %clang_cc1 %s -ffp-exception-behavior=maytrap -DSET -emit-pch -o %t +// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s +// RUN: %clang_cc1 %s -ffp-contract=fast -DSET -emit-pch -o %t +// RUN: %clang_cc1 %s -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-EBSTRICT %s +// RUN: %clang_cc1 %s -DSET -emit-pch -o %t +// RUN: %clang_cc1 %s -ffp-contract=on -DSET -include-pch %t -emit-llvm -o - | FileCheck --check-prefix=CHECK-CONTRACT %s // RUN: %clang_cc1 %s -DPUSH -emit-pch -o %t // RUN: %clang_cc1 %s -DPUSH -verify -include-pch %t // RUN: %clang_cc1 %s -DPUSH_POP -emit-pch -o %t @@ -36,6 +48,7 @@ // CHECK-LABEL: define float @fun{{.*}} //CHECK-EBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict //CHECK-EBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}strict + //CHECK-CONTRACT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict return a * b + 2; } #pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}} diff --git a/clang/test/SemaOpenCL/fp-options.cl b/clang/test/SemaOpenCL/fp-options.cl new file mode 100644 --- /dev/null +++ b/clang/test/SemaOpenCL/fp-options.cl @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 %s -finclude-default-header -triple spir-unknown-unknown -emit-pch -o %t.pch +// RUN: %clang_cc1 %s -finclude-default-header -cl-no-signed-zeros -triple spir-unknown-unknown -include-pch %t.pch -fsyntax-only -verify +// expected-no-diagnostics +