[clang] Enable support for #pragma STDC FENV_ACCESS
Reviewers: rjmccall, rsmith, sepavloff Differential Revision: https://reviews.llvm.org/D87528
This commit is contained in:
parent
3052e474ec
commit
2e204e2391
|
@ -1386,7 +1386,7 @@ Note that floating-point operations performed as part of constant initialization
|
||||||
Details:
|
Details:
|
||||||
|
|
||||||
* ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=fast``). This is the default behavior.
|
* ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=fast``). This is the default behavior.
|
||||||
* ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled.
|
* ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled. Enables ``STDC FENV_ACCESS``: by default ``FENV_ACCESS`` is disabled. This option setting behaves as though ``#pragma STDC FENV_ACESS ON`` appeared at the top of the source file.
|
||||||
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast``
|
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast``
|
||||||
|
|
||||||
Note: If your command line specifies multiple instances
|
Note: If your command line specifies multiple instances
|
||||||
|
@ -1408,6 +1408,44 @@ Note that floating-point operations performed as part of constant initialization
|
||||||
* ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code.
|
* ``strict`` The compiler ensures that all transformations strictly preserve the floating point exception semantics of the original code.
|
||||||
|
|
||||||
|
|
||||||
|
.. _fp-constant-eval:
|
||||||
|
|
||||||
|
A note about Floating Point Constant Evaluation
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
In C, the only place floating point operations are guaranteed to be evaluated
|
||||||
|
during translation is in the initializers of variables of static storage
|
||||||
|
duration, which are all notionally initialized before the program begins
|
||||||
|
executing (and thus before a non-default floating point environment can be
|
||||||
|
entered). But C++ has many more contexts where floating point constant
|
||||||
|
evaluation occurs. Specifically: for static/thread-local variables,
|
||||||
|
first try evaluating the initializer in a constant context, including in the
|
||||||
|
constant floating point environment (just like in C), and then, if that fails,
|
||||||
|
fall back to emitting runtime code to perform the initialization (which might
|
||||||
|
in general be in a different floating point environment).
|
||||||
|
|
||||||
|
Consider this example when compiled with ``-frounding-math``
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
constexpr float func_01(float x, float y) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
float V1 = func_01(1.0F, 0x0.000001p0F);
|
||||||
|
|
||||||
|
The C++ rule is that initializers for static storage duration variables are
|
||||||
|
first evaluated during translation (therefore, in the default rounding mode),
|
||||||
|
and only evaluated at runtime (and therefore in the runtime rounding mode) if
|
||||||
|
the compile-time evaluation fails. This is in line with the C rules;
|
||||||
|
C11 F.8.5 says: *All computation for automatic initialization is done (as if)
|
||||||
|
at execution time; thus, it is affected by any operative modes and raises
|
||||||
|
floating-point exceptions as required by IEC 60559 (provided the state for the
|
||||||
|
FENV_ACCESS pragma is ‘‘on’’). All computation for initialization of objects
|
||||||
|
that have static or thread storage duration is done (as if) at translation
|
||||||
|
time.* C++ generalizes this by adding another phase of initialization
|
||||||
|
(at runtime) if the translation-time initialization fails, but the
|
||||||
|
translation-time evaluation of the initializer of succeeds, it will be
|
||||||
|
treated as a constant initializer.
|
||||||
|
|
||||||
|
|
||||||
.. _controlling-code-generation:
|
.. _controlling-code-generation:
|
||||||
|
|
|
@ -2253,10 +2253,6 @@ public:
|
||||||
bool usesSEHTry() const { return FunctionDeclBits.UsesSEHTry; }
|
bool usesSEHTry() const { return FunctionDeclBits.UsesSEHTry; }
|
||||||
void setUsesSEHTry(bool UST) { FunctionDeclBits.UsesSEHTry = UST; }
|
void setUsesSEHTry(bool UST) { FunctionDeclBits.UsesSEHTry = UST; }
|
||||||
|
|
||||||
/// Indicates the function uses Floating Point constrained intrinsics
|
|
||||||
bool usesFPIntrin() const { return FunctionDeclBits.UsesFPIntrin; }
|
|
||||||
void setUsesFPIntrin(bool Val) { FunctionDeclBits.UsesFPIntrin = Val; }
|
|
||||||
|
|
||||||
/// Whether this function has been deleted.
|
/// Whether this function has been deleted.
|
||||||
///
|
///
|
||||||
/// A function that is "deleted" (via the C++0x "= delete" syntax)
|
/// A function that is "deleted" (via the C++0x "= delete" syntax)
|
||||||
|
|
|
@ -2267,6 +2267,14 @@ def PragmaClangRelroSection : InheritableAttr {
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def StrictFP : InheritableAttr {
|
||||||
|
// This attribute has no spellings as it is only ever created implicitly.
|
||||||
|
// Function uses strict floating point operations.
|
||||||
|
let Spellings = [];
|
||||||
|
let Subjects = SubjectList<[Function]>;
|
||||||
|
let Documentation = [Undocumented];
|
||||||
|
}
|
||||||
|
|
||||||
def PragmaClangTextSection : InheritableAttr {
|
def PragmaClangTextSection : InheritableAttr {
|
||||||
// This attribute has no spellings as it is only ever created implicitly.
|
// This attribute has no spellings as it is only ever created implicitly.
|
||||||
let Spellings = [];
|
let Spellings = [];
|
||||||
|
|
|
@ -74,6 +74,8 @@ def note_constexpr_float_arithmetic : Note<
|
||||||
"floating point arithmetic produces %select{an infinity|a NaN}0">;
|
"floating point arithmetic produces %select{an infinity|a NaN}0">;
|
||||||
def note_constexpr_dynamic_rounding : Note<
|
def note_constexpr_dynamic_rounding : Note<
|
||||||
"cannot evaluate this expression if rounding mode is dynamic">;
|
"cannot evaluate this expression if rounding mode is dynamic">;
|
||||||
|
def note_constexpr_float_arithmetic_strict : Note<
|
||||||
|
"compile time floating point arithmetic suppressed in strict evaluation modes">;
|
||||||
def note_constexpr_pointer_subtraction_not_same_array : Note<
|
def note_constexpr_pointer_subtraction_not_same_array : Note<
|
||||||
"subtracted pointers are not elements of the same array">;
|
"subtracted pointers are not elements of the same array">;
|
||||||
def note_constexpr_pointer_subtraction_zero_size : Note<
|
def note_constexpr_pointer_subtraction_zero_size : Note<
|
||||||
|
|
|
@ -1135,9 +1135,12 @@ def err_pragma_file_or_compound_scope : Error<
|
||||||
// - #pragma stdc unknown
|
// - #pragma stdc unknown
|
||||||
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
|
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
|
||||||
InGroup<UnknownPragmas>;
|
InGroup<UnknownPragmas>;
|
||||||
def warn_stdc_fenv_access_not_supported :
|
// The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either
|
||||||
Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
|
// outside external declarations or preceding all explicit declarations and
|
||||||
InGroup<UnknownPragmas>;
|
// statements inside a compound statement.
|
||||||
|
def err_pragma_stdc_fenv_access_scope : Error<
|
||||||
|
"'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of"
|
||||||
|
" a compound statement">;
|
||||||
def warn_stdc_fenv_round_not_supported :
|
def warn_stdc_fenv_round_not_supported :
|
||||||
Warning<"pragma STDC FENV_ROUND is not supported">,
|
Warning<"pragma STDC FENV_ROUND is not supported">,
|
||||||
InGroup<UnknownPragmas>;
|
InGroup<UnknownPragmas>;
|
||||||
|
|
|
@ -413,13 +413,20 @@ public:
|
||||||
setFPContractMode(LO.getDefaultFPContractMode());
|
setFPContractMode(LO.getDefaultFPContractMode());
|
||||||
setRoundingMode(LO.getFPRoundingMode());
|
setRoundingMode(LO.getFPRoundingMode());
|
||||||
setFPExceptionMode(LO.getFPExceptionMode());
|
setFPExceptionMode(LO.getFPExceptionMode());
|
||||||
setAllowFEnvAccess(LangOptions::FPM_Off);
|
|
||||||
setAllowFPReassociate(LO.AllowFPReassoc);
|
setAllowFPReassociate(LO.AllowFPReassoc);
|
||||||
setNoHonorNaNs(LO.NoHonorNaNs);
|
setNoHonorNaNs(LO.NoHonorNaNs);
|
||||||
setNoHonorInfs(LO.NoHonorInfs);
|
setNoHonorInfs(LO.NoHonorInfs);
|
||||||
setNoSignedZero(LO.NoSignedZero);
|
setNoSignedZero(LO.NoSignedZero);
|
||||||
setAllowReciprocal(LO.AllowRecip);
|
setAllowReciprocal(LO.AllowRecip);
|
||||||
setAllowApproxFunc(LO.ApproxFunc);
|
setAllowApproxFunc(LO.ApproxFunc);
|
||||||
|
if (getFPContractMode() == LangOptions::FPM_On &&
|
||||||
|
getRoundingMode() == llvm::RoundingMode::Dynamic &&
|
||||||
|
getFPExceptionMode() == LangOptions::FPE_Strict)
|
||||||
|
// If the FP settings are set to the "strict" model, then
|
||||||
|
// FENV access is set to true. (ffp-model=strict)
|
||||||
|
setAllowFEnvAccess(true);
|
||||||
|
else
|
||||||
|
setAllowFEnvAccess(LangOptions::FPM_Off);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allowFPContractWithinStatement() const {
|
bool allowFPContractWithinStatement() const {
|
||||||
|
|
|
@ -127,6 +127,9 @@ public:
|
||||||
/// Whether there is a fallthrough statement in this function.
|
/// Whether there is a fallthrough statement in this function.
|
||||||
bool HasFallthroughStmt : 1;
|
bool HasFallthroughStmt : 1;
|
||||||
|
|
||||||
|
/// Whether this function uses constrained floating point intrinsics
|
||||||
|
bool UsesFPIntrin : 1;
|
||||||
|
|
||||||
/// Whether we make reference to a declaration that could be
|
/// Whether we make reference to a declaration that could be
|
||||||
/// unavailable.
|
/// unavailable.
|
||||||
bool HasPotentialAvailabilityViolations : 1;
|
bool HasPotentialAvailabilityViolations : 1;
|
||||||
|
@ -369,7 +372,8 @@ public:
|
||||||
: Kind(SK_Function), HasBranchProtectedScope(false),
|
: Kind(SK_Function), HasBranchProtectedScope(false),
|
||||||
HasBranchIntoScope(false), HasIndirectGoto(false),
|
HasBranchIntoScope(false), HasIndirectGoto(false),
|
||||||
HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false),
|
HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false),
|
||||||
HasFallthroughStmt(false), HasPotentialAvailabilityViolations(false),
|
HasFallthroughStmt(false), UsesFPIntrin(false),
|
||||||
|
HasPotentialAvailabilityViolations(false),
|
||||||
ObjCShouldCallSuper(false), ObjCIsDesignatedInit(false),
|
ObjCShouldCallSuper(false), ObjCIsDesignatedInit(false),
|
||||||
ObjCWarnForNoDesignatedInitChain(false), ObjCIsSecondaryInit(false),
|
ObjCWarnForNoDesignatedInitChain(false), ObjCIsSecondaryInit(false),
|
||||||
ObjCWarnForNoInitDelegation(false), NeedsCoroutineSuspends(true),
|
ObjCWarnForNoInitDelegation(false), NeedsCoroutineSuspends(true),
|
||||||
|
@ -431,6 +435,10 @@ public:
|
||||||
HasFallthroughStmt = true;
|
HasFallthroughStmt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUsesFPIntrin() {
|
||||||
|
UsesFPIntrin = true;
|
||||||
|
}
|
||||||
|
|
||||||
void setHasCXXTry(SourceLocation TryLoc) {
|
void setHasCXXTry(SourceLocation TryLoc) {
|
||||||
setHasBranchProtectedScope();
|
setHasBranchProtectedScope();
|
||||||
FirstCXXTryLoc = TryLoc;
|
FirstCXXTryLoc = TryLoc;
|
||||||
|
|
|
@ -4478,6 +4478,7 @@ public:
|
||||||
bool HasLeadingEmptyMacro = false);
|
bool HasLeadingEmptyMacro = false);
|
||||||
|
|
||||||
void ActOnStartOfCompoundStmt(bool IsStmtExpr);
|
void ActOnStartOfCompoundStmt(bool IsStmtExpr);
|
||||||
|
void ActOnAfterCompoundStatementLeadingPragmas();
|
||||||
void ActOnFinishOfCompoundStmt();
|
void ActOnFinishOfCompoundStmt();
|
||||||
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
||||||
ArrayRef<Stmt *> Elts, bool isStmtExpr);
|
ArrayRef<Stmt *> Elts, bool isStmtExpr);
|
||||||
|
|
|
@ -2601,6 +2601,14 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((St != APFloat::opOK) &&
|
||||||
|
(FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
|
||||||
|
FPO.getFPExceptionMode() != LangOptions::FPE_Ignore ||
|
||||||
|
FPO.getAllowFEnvAccess())) {
|
||||||
|
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((St & APFloat::opStatus::opInvalidOp) &&
|
if ((St & APFloat::opStatus::opInvalidOp) &&
|
||||||
FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) {
|
FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) {
|
||||||
// There is no usefully definable result.
|
// There is no usefully definable result.
|
||||||
|
@ -2644,11 +2652,17 @@ static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
|
static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
|
||||||
|
const FPOptions FPO,
|
||||||
QualType SrcType, const APSInt &Value,
|
QualType SrcType, const APSInt &Value,
|
||||||
QualType DestType, APFloat &Result) {
|
QualType DestType, APFloat &Result) {
|
||||||
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
|
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
|
||||||
Result.convertFromAPInt(Value, Value.isSigned(),
|
APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(),
|
||||||
APFloat::rmNearestTiesToEven);
|
APFloat::rmNearestTiesToEven);
|
||||||
|
if (!Info.InConstantContext && St != llvm::APFloatBase::opOK &&
|
||||||
|
FPO.isFPConstrained()) {
|
||||||
|
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4370,9 +4384,11 @@ struct CompoundAssignSubobjectHandler {
|
||||||
Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
|
Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
|
||||||
return true;
|
return true;
|
||||||
} else if (RHS.isFloat()) {
|
} else if (RHS.isFloat()) {
|
||||||
|
const FPOptions FPO = E->getFPFeaturesInEffect(
|
||||||
|
Info.Ctx.getLangOpts());
|
||||||
APFloat FValue(0.0);
|
APFloat FValue(0.0);
|
||||||
return HandleIntToFloatCast(Info, E, SubobjType, Value, PromotedLHSType,
|
return HandleIntToFloatCast(Info, E, FPO, SubobjType, Value,
|
||||||
FValue) &&
|
PromotedLHSType, FValue) &&
|
||||||
handleFloatFloatBinOp(Info, E, FValue, Opcode, RHS.getFloat()) &&
|
handleFloatFloatBinOp(Info, E, FValue, Opcode, RHS.getFloat()) &&
|
||||||
HandleFloatToIntCast(Info, E, PromotedLHSType, FValue, SubobjType,
|
HandleFloatToIntCast(Info, E, PromotedLHSType, FValue, SubobjType,
|
||||||
Value);
|
Value);
|
||||||
|
@ -12545,8 +12561,16 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
assert(E->isComparisonOp() && "Invalid binary operator!");
|
assert(E->isComparisonOp() && "Invalid binary operator!");
|
||||||
|
llvm::APFloatBase::cmpResult CmpResult = LHS.compare(RHS);
|
||||||
|
if (!Info.InConstantContext &&
|
||||||
|
CmpResult == APFloat::cmpUnordered &&
|
||||||
|
E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained()) {
|
||||||
|
// Note: Compares may raise invalid in some cases involving NaN or sNaN.
|
||||||
|
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
auto GetCmpRes = [&]() {
|
auto GetCmpRes = [&]() {
|
||||||
switch (LHS.compare(RHS)) {
|
switch (CmpResult) {
|
||||||
case APFloat::cmpEqual:
|
case APFloat::cmpEqual:
|
||||||
return CmpResult::Equal;
|
return CmpResult::Equal;
|
||||||
case APFloat::cmpLessThan:
|
case APFloat::cmpLessThan:
|
||||||
|
@ -13604,6 +13628,11 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
||||||
case Builtin::BI__builtin_fabsf:
|
case Builtin::BI__builtin_fabsf:
|
||||||
case Builtin::BI__builtin_fabsl:
|
case Builtin::BI__builtin_fabsl:
|
||||||
case Builtin::BI__builtin_fabsf128:
|
case Builtin::BI__builtin_fabsf128:
|
||||||
|
// The C standard says "fabs raises no floating-point exceptions,
|
||||||
|
// even if x is a signaling NaN. The returned value is independent of
|
||||||
|
// the current rounding direction mode." Therefore constant folding can
|
||||||
|
// proceed without regard to the floating point settings.
|
||||||
|
// Reference, WG14 N2478 F.10.4.3
|
||||||
if (!EvaluateFloat(E->getArg(0), Result, Info))
|
if (!EvaluateFloat(E->getArg(0), Result, Info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -13662,6 +13691,9 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
|
||||||
case UO_Plus:
|
case UO_Plus:
|
||||||
return EvaluateFloat(E->getSubExpr(), Result, Info);
|
return EvaluateFloat(E->getSubExpr(), Result, Info);
|
||||||
case UO_Minus:
|
case UO_Minus:
|
||||||
|
// In C standard, WG14 N2478 F.3 p4
|
||||||
|
// "the unary - raises no floating point exceptions,
|
||||||
|
// even if the operand is signalling."
|
||||||
if (!EvaluateFloat(E->getSubExpr(), Result, Info))
|
if (!EvaluateFloat(E->getSubExpr(), Result, Info))
|
||||||
return false;
|
return false;
|
||||||
Result.changeSign();
|
Result.changeSign();
|
||||||
|
@ -13695,9 +13727,11 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||||
|
|
||||||
case CK_IntegralToFloating: {
|
case CK_IntegralToFloating: {
|
||||||
APSInt IntResult;
|
APSInt IntResult;
|
||||||
|
const FPOptions FPO = E->getFPFeaturesInEffect(
|
||||||
|
Info.Ctx.getLangOpts());
|
||||||
return EvaluateInteger(SubExpr, IntResult, Info) &&
|
return EvaluateInteger(SubExpr, IntResult, Info) &&
|
||||||
HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult,
|
HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(),
|
||||||
E->getType(), Result);
|
IntResult, E->getType(), Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
case CK_FixedPointToFloating: {
|
case CK_FixedPointToFloating: {
|
||||||
|
@ -13936,13 +13970,15 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||||
if (!Visit(E->getSubExpr()))
|
if (!Visit(E->getSubExpr()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const FPOptions FPO = E->getFPFeaturesInEffect(
|
||||||
|
Info.Ctx.getLangOpts());
|
||||||
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
|
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
|
||||||
QualType From
|
QualType From
|
||||||
= E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
|
= E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
|
||||||
Result.makeComplexFloat();
|
Result.makeComplexFloat();
|
||||||
return HandleIntToFloatCast(Info, E, From, Result.IntReal,
|
return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal,
|
||||||
To, Result.FloatReal) &&
|
To, Result.FloatReal) &&
|
||||||
HandleIntToFloatCast(Info, E, From, Result.IntImag,
|
HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag,
|
||||||
To, Result.FloatImag);
|
To, Result.FloatImag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4837,7 +4837,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||||
/*AttrOnCallSite=*/true);
|
/*AttrOnCallSite=*/true);
|
||||||
|
|
||||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
|
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
|
||||||
if (FD->usesFPIntrin())
|
if (FD->hasAttr<StrictFPAttr>())
|
||||||
// All calls within a strictfp function are marked strictfp
|
// All calls within a strictfp function are marked strictfp
|
||||||
Attrs =
|
Attrs =
|
||||||
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
|
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
|
||||||
|
@ -4902,7 +4902,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||||
getBundlesForFunclet(CalleePtr);
|
getBundlesForFunclet(CalleePtr);
|
||||||
|
|
||||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
|
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
|
||||||
if (FD->usesFPIntrin())
|
if (FD->hasAttr<StrictFPAttr>())
|
||||||
// All calls within a strictfp function are marked strictfp
|
// All calls within a strictfp function are marked strictfp
|
||||||
Attrs =
|
Attrs =
|
||||||
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
|
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
|
||||||
|
|
|
@ -915,8 +915,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||||
Builder.setIsFPConstrained(FD->usesFPIntrin());
|
Builder.setIsFPConstrained(FD->hasAttr<StrictFPAttr>());
|
||||||
if (FD->usesFPIntrin())
|
if (FD->hasAttr<StrictFPAttr>())
|
||||||
Fn->addFnAttr(llvm::Attribute::StrictFP);
|
Fn->addFnAttr(llvm::Attribute::StrictFP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1742,6 +1742,15 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D,
|
||||||
|
llvm::Function *F) {
|
||||||
|
if (D->hasAttr<StrictFPAttr>()) {
|
||||||
|
llvm::AttrBuilder FuncAttrs;
|
||||||
|
FuncAttrs.addAttribute("strictfp");
|
||||||
|
F->addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) {
|
void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) {
|
||||||
const Decl *D = GD.getDecl();
|
const Decl *D = GD.getDecl();
|
||||||
if (dyn_cast_or_null<NamedDecl>(D))
|
if (dyn_cast_or_null<NamedDecl>(D))
|
||||||
|
@ -4587,9 +4596,11 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
|
||||||
|
|
||||||
MaybeHandleStaticInExternC(D, Fn);
|
MaybeHandleStaticInExternC(D, Fn);
|
||||||
|
|
||||||
|
|
||||||
maybeSetTrivialComdat(*D, *Fn);
|
maybeSetTrivialComdat(*D, *Fn);
|
||||||
|
|
||||||
|
// Set CodeGen attributes that represent floating point environment.
|
||||||
|
setLLVMFunctionFEnvAttributes(D, Fn);
|
||||||
|
|
||||||
CodeGenFunction(*this).GenerateCode(GD, Fn, FI);
|
CodeGenFunction(*this).GenerateCode(GD, Fn, FI);
|
||||||
|
|
||||||
setNonAliasAttributes(GD, Fn);
|
setNonAliasAttributes(GD, Fn);
|
||||||
|
|
|
@ -1131,6 +1131,10 @@ public:
|
||||||
/// definition.
|
/// definition.
|
||||||
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
|
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
|
||||||
|
|
||||||
|
/// Set the LLVM function attributes that represent floating point
|
||||||
|
/// environment.
|
||||||
|
void setLLVMFunctionFEnvAttributes(const FunctionDecl *D, llvm::Function *F);
|
||||||
|
|
||||||
/// Return true iff the given type uses 'sret' when used as a return type.
|
/// Return true iff the given type uses 'sret' when used as a return type.
|
||||||
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
|
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
|
||||||
|
|
||||||
|
|
|
@ -106,10 +106,6 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
|
||||||
tok::OnOffSwitch OOS;
|
tok::OnOffSwitch OOS;
|
||||||
if (PP.LexOnOffSwitch(OOS))
|
if (PP.LexOnOffSwitch(OOS))
|
||||||
return;
|
return;
|
||||||
if (OOS == tok::OOS_ON) {
|
|
||||||
PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
|
MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
|
||||||
1);
|
1);
|
||||||
|
|
|
@ -366,7 +366,8 @@ Retry:
|
||||||
|
|
||||||
case tok::annot_pragma_fenv_access:
|
case tok::annot_pragma_fenv_access:
|
||||||
ProhibitAttributes(Attrs);
|
ProhibitAttributes(Attrs);
|
||||||
HandlePragmaFEnvAccess();
|
Diag(Tok, diag::err_pragma_stdc_fenv_access_scope);
|
||||||
|
ConsumeAnnotationToken();
|
||||||
return StmtEmpty();
|
return StmtEmpty();
|
||||||
|
|
||||||
case tok::annot_pragma_fenv_round:
|
case tok::annot_pragma_fenv_round:
|
||||||
|
@ -1033,9 +1034,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
||||||
Tok.getLocation(),
|
Tok.getLocation(),
|
||||||
"in compound statement ('{}')");
|
"in compound statement ('{}')");
|
||||||
|
|
||||||
// Record the state of the FPFeatures, restore on leaving the
|
// Record the current FPFeatures, restore on leaving the
|
||||||
// compound statement.
|
// compound statement.
|
||||||
Sema::FPFeaturesStateRAII SaveFPContractState(Actions);
|
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
|
||||||
|
|
||||||
InMessageExpressionRAIIObject InMessage(*this, false);
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
||||||
BalancedDelimiterTracker T(*this, tok::l_brace);
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
||||||
|
@ -1046,6 +1047,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
||||||
|
|
||||||
// Parse any pragmas at the beginning of the compound statement.
|
// Parse any pragmas at the beginning of the compound statement.
|
||||||
ParseCompoundStatementLeadingPragmas();
|
ParseCompoundStatementLeadingPragmas();
|
||||||
|
Actions.ActOnAfterCompoundStatementLeadingPragmas();
|
||||||
|
|
||||||
StmtVector Stmts;
|
StmtVector Stmts;
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ void FunctionScopeInfo::Clear() {
|
||||||
HasDroppedStmt = false;
|
HasDroppedStmt = false;
|
||||||
HasOMPDeclareReductionCombiner = false;
|
HasOMPDeclareReductionCombiner = false;
|
||||||
HasFallthroughStmt = false;
|
HasFallthroughStmt = false;
|
||||||
|
UsesFPIntrin = false;
|
||||||
HasPotentialAvailabilityViolations = false;
|
HasPotentialAvailabilityViolations = false;
|
||||||
ObjCShouldCallSuper = false;
|
ObjCShouldCallSuper = false;
|
||||||
ObjCIsDesignatedInit = false;
|
ObjCIsDesignatedInit = false;
|
||||||
|
|
|
@ -1002,6 +1002,7 @@ void Sema::setExceptionMode(SourceLocation Loc,
|
||||||
|
|
||||||
void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
|
void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
|
||||||
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
||||||
|
auto LO = getLangOpts();
|
||||||
if (IsEnabled) {
|
if (IsEnabled) {
|
||||||
// Verify Microsoft restriction:
|
// Verify Microsoft restriction:
|
||||||
// You can't enable fenv_access unless precise semantics are enabled.
|
// You can't enable fenv_access unless precise semantics are enabled.
|
||||||
|
@ -1010,10 +1011,15 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
|
||||||
if (!isPreciseFPEnabled())
|
if (!isPreciseFPEnabled())
|
||||||
Diag(Loc, diag::err_pragma_fenv_requires_precise);
|
Diag(Loc, diag::err_pragma_fenv_requires_precise);
|
||||||
NewFPFeatures.setAllowFEnvAccessOverride(true);
|
NewFPFeatures.setAllowFEnvAccessOverride(true);
|
||||||
} else
|
// Enabling FENV access sets the RoundingMode to Dynamic.
|
||||||
|
// and ExceptionBehavior to Strict
|
||||||
|
NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic);
|
||||||
|
NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
|
||||||
|
} else {
|
||||||
NewFPFeatures.setAllowFEnvAccessOverride(false);
|
NewFPFeatures.setAllowFEnvAccessOverride(false);
|
||||||
|
}
|
||||||
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
||||||
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
|
CurFPFeatures = NewFPFeatures.applyOverrides(LO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
|
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
|
||||||
|
|
|
@ -14285,12 +14285,16 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) {
|
||||||
|
|
||||||
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
bool IsInstantiation) {
|
bool IsInstantiation) {
|
||||||
|
FunctionScopeInfo *FSI = getCurFunction();
|
||||||
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
|
FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
|
||||||
|
|
||||||
|
if (FSI->UsesFPIntrin && !FD->hasAttr<StrictFPAttr>())
|
||||||
|
FD->addAttr(StrictFPAttr::CreateImplicit(Context));
|
||||||
|
|
||||||
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
|
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
|
||||||
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
|
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
|
||||||
|
|
||||||
if (getLangOpts().Coroutines && getCurFunction()->isCoroutine())
|
if (getLangOpts().Coroutines && FSI->isCoroutine())
|
||||||
CheckCompletedCoroutineBody(FD, Body);
|
CheckCompletedCoroutineBody(FD, Body);
|
||||||
|
|
||||||
// Do not call PopExpressionEvaluationContext() if it is a lambda because one
|
// Do not call PopExpressionEvaluationContext() if it is a lambda because one
|
||||||
|
@ -14367,7 +14371,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
// to deduce an implicit return type.
|
// to deduce an implicit return type.
|
||||||
if (FD->getReturnType()->isRecordType() &&
|
if (FD->getReturnType()->isRecordType() &&
|
||||||
(!getLangOpts().CPlusPlus || !FD->isDependentContext()))
|
(!getLangOpts().CPlusPlus || !FD->isDependentContext()))
|
||||||
computeNRVO(Body, getCurFunction());
|
computeNRVO(Body, FSI);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GNU warning -Wmissing-prototypes:
|
// GNU warning -Wmissing-prototypes:
|
||||||
|
@ -14491,14 +14495,14 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
MD->getReturnType(), MD);
|
MD->getReturnType(), MD);
|
||||||
|
|
||||||
if (Body)
|
if (Body)
|
||||||
computeNRVO(Body, getCurFunction());
|
computeNRVO(Body, FSI);
|
||||||
}
|
}
|
||||||
if (getCurFunction()->ObjCShouldCallSuper) {
|
if (FSI->ObjCShouldCallSuper) {
|
||||||
Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call)
|
Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call)
|
||||||
<< MD->getSelector().getAsString();
|
<< MD->getSelector().getAsString();
|
||||||
getCurFunction()->ObjCShouldCallSuper = false;
|
FSI->ObjCShouldCallSuper = false;
|
||||||
}
|
}
|
||||||
if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) {
|
if (FSI->ObjCWarnForNoDesignatedInitChain) {
|
||||||
const ObjCMethodDecl *InitMethod = nullptr;
|
const ObjCMethodDecl *InitMethod = nullptr;
|
||||||
bool isDesignated =
|
bool isDesignated =
|
||||||
MD->isDesignatedInitializerForTheInterface(&InitMethod);
|
MD->isDesignatedInitializerForTheInterface(&InitMethod);
|
||||||
|
@ -14523,14 +14527,14 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
Diag(InitMethod->getLocation(),
|
Diag(InitMethod->getLocation(),
|
||||||
diag::note_objc_designated_init_marked_here);
|
diag::note_objc_designated_init_marked_here);
|
||||||
}
|
}
|
||||||
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
|
FSI->ObjCWarnForNoDesignatedInitChain = false;
|
||||||
}
|
}
|
||||||
if (getCurFunction()->ObjCWarnForNoInitDelegation) {
|
if (FSI->ObjCWarnForNoInitDelegation) {
|
||||||
// Don't issue this warning for unavaialable inits.
|
// Don't issue this warning for unavaialable inits.
|
||||||
if (!MD->isUnavailable())
|
if (!MD->isUnavailable())
|
||||||
Diag(MD->getLocation(),
|
Diag(MD->getLocation(),
|
||||||
diag::warn_objc_secondary_init_missing_init_call);
|
diag::warn_objc_secondary_init_missing_init_call);
|
||||||
getCurFunction()->ObjCWarnForNoInitDelegation = false;
|
FSI->ObjCWarnForNoInitDelegation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnoseImplicitlyRetainedSelf(*this);
|
diagnoseImplicitlyRetainedSelf(*this);
|
||||||
|
@ -14541,10 +14545,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Body && getCurFunction()->HasPotentialAvailabilityViolations)
|
if (Body && FSI->HasPotentialAvailabilityViolations)
|
||||||
DiagnoseUnguardedAvailabilityViolations(dcl);
|
DiagnoseUnguardedAvailabilityViolations(dcl);
|
||||||
|
|
||||||
assert(!getCurFunction()->ObjCShouldCallSuper &&
|
assert(!FSI->ObjCShouldCallSuper &&
|
||||||
"This should only be set for ObjC methods, which should have been "
|
"This should only be set for ObjC methods, which should have been "
|
||||||
"handled in the block above.");
|
"handled in the block above.");
|
||||||
|
|
||||||
|
@ -14557,7 +14561,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
||||||
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
|
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
|
||||||
|
|
||||||
// Verify that gotos and switch cases don't jump into scopes illegally.
|
// Verify that gotos and switch cases don't jump into scopes illegally.
|
||||||
if (getCurFunction()->NeedsScopeChecking() &&
|
if (FSI->NeedsScopeChecking() &&
|
||||||
!PP.isCodeCompletionEnabled())
|
!PP.isCodeCompletionEnabled())
|
||||||
DiagnoseInvalidJumps(Body);
|
DiagnoseInvalidJumps(Body);
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,14 @@ void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
|
||||||
PushCompoundScope(IsStmtExpr);
|
PushCompoundScope(IsStmtExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sema::ActOnAfterCompoundStatementLeadingPragmas() {
|
||||||
|
if (getCurFPFeatures().isFPConstrained()) {
|
||||||
|
FunctionScopeInfo *FSI = getCurFunction();
|
||||||
|
assert(FSI);
|
||||||
|
FSI->setUsesFPIntrin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::ActOnFinishOfCompoundStmt() {
|
void Sema::ActOnFinishOfCompoundStmt() {
|
||||||
PopCompoundScope();
|
PopCompoundScope();
|
||||||
}
|
}
|
||||||
|
@ -397,11 +405,6 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
|
||||||
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
|
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
|
||||||
const unsigned NumElts = Elts.size();
|
const unsigned NumElts = Elts.size();
|
||||||
|
|
||||||
// Mark the current function as usng floating point constrained intrinsics
|
|
||||||
if (getCurFPFeatures().isFPConstrained())
|
|
||||||
if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext))
|
|
||||||
F->setUsesFPIntrin(true);
|
|
||||||
|
|
||||||
// If we're in C89 mode, check that we don't have any decls after stmts. If
|
// If we're in C89 mode, check that we don't have any decls after stmts. If
|
||||||
// so, emit an extension diagnostic.
|
// so, emit an extension diagnostic.
|
||||||
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
|
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
|
||||||
|
|
|
@ -1951,7 +1951,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
|
||||||
D->hasWrittenPrototype(), D->getConstexprKind(),
|
D->hasWrittenPrototype(), D->getConstexprKind(),
|
||||||
TrailingRequiresClause);
|
TrailingRequiresClause);
|
||||||
Function->setRangeEnd(D->getSourceRange().getEnd());
|
Function->setRangeEnd(D->getSourceRange().getEnd());
|
||||||
Function->setUsesFPIntrin(D->usesFPIntrin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (D->isInlined())
|
if (D->isInlined())
|
||||||
|
|
|
@ -888,7 +888,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
|
||||||
|
|
||||||
FD->ODRHash = Record.readInt();
|
FD->ODRHash = Record.readInt();
|
||||||
FD->setHasODRHash(true);
|
FD->setHasODRHash(true);
|
||||||
FD->setUsesFPIntrin(Record.readInt());
|
|
||||||
|
|
||||||
if (FD->isDefaulted()) {
|
if (FD->isDefaulted()) {
|
||||||
if (unsigned NumLookups = Record.readInt()) {
|
if (unsigned NumLookups = Record.readInt()) {
|
||||||
|
|
|
@ -566,7 +566,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
Record.AddSourceLocation(D->getEndLoc());
|
Record.AddSourceLocation(D->getEndLoc());
|
||||||
|
|
||||||
Record.push_back(D->getODRHash());
|
Record.push_back(D->getODRHash());
|
||||||
Record.push_back(D->usesFPIntrin());
|
|
||||||
|
|
||||||
if (D->isDefaulted()) {
|
if (D->isDefaulted()) {
|
||||||
if (auto *FDI = D->getDefaultedFunctionInfo()) {
|
if (auto *FDI = D->getDefaultedFunctionInfo()) {
|
||||||
|
|
|
@ -280,6 +280,16 @@ namespace UndefinedBehavior {
|
||||||
constexpr float f10 = f2 - f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
constexpr float f10 = f2 - f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
||||||
constexpr float f11 = f2 + f4; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
constexpr float f11 = f2 + f4; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
||||||
constexpr float f12 = f2 / f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
constexpr float f12 = f2 / f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
|
||||||
|
#pragma float_control(push)
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
constexpr float pi = 3.14f;
|
||||||
|
constexpr unsigned ubig = 0xFFFFFFFF;
|
||||||
|
constexpr float ce = 1.0 / 3.0; // not-expected-error {{constant expression}} not-expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
|
||||||
|
constexpr int ci = (int) pi;
|
||||||
|
constexpr float fbig = (float) ubig; // not-expected-error {{constant expression}} not-expected-note {{floating point arithmetic suppressed in strict evaluation modes}}
|
||||||
|
constexpr float fabspi = __builtin_fabs(pi); // no error expected
|
||||||
|
constexpr float negpi = -pi; // expect no error on unary operator
|
||||||
|
#pragma float_control(pop)
|
||||||
static_assert(!isinf(f1), "");
|
static_assert(!isinf(f1), "");
|
||||||
static_assert(isinf(f2), "");
|
static_assert(isinf(f2), "");
|
||||||
static_assert(!isinf(f3), "");
|
static_assert(!isinf(f3), "");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// RUN: %clang_cc1 -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s
|
// RUN: %clang_cc1 -DEXCEPT=1 -fcxx-exceptions -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-NS %s
|
||||||
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||||
// RUN: %clang_cc1 -verify -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
// RUN: %clang_cc1 -DFENV_ON=1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-FENV %s
|
||||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -O3 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-O3 %s
|
||||||
|
|
||||||
// Verify float_control(precise, off) enables fast math flags on fp operations.
|
// Verify float_control(precise, off) enables fast math flags on fp operations.
|
||||||
|
@ -138,7 +138,6 @@ float test_OperatorCall() {
|
||||||
// CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}}
|
// CHECK-LABEL define float {{.*}}test_OperatorCall{{.*}}
|
||||||
|
|
||||||
#if FENV_ON
|
#if FENV_ON
|
||||||
// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
|
|
||||||
#pragma STDC FENV_ACCESS ON
|
#pragma STDC FENV_ACCESS ON
|
||||||
#endif
|
#endif
|
||||||
// CHECK-LABEL: define {{.*}}callt{{.*}}
|
// CHECK-LABEL: define {{.*}}callt{{.*}}
|
||||||
|
@ -146,7 +145,21 @@ float test_OperatorCall() {
|
||||||
void callt() {
|
void callt() {
|
||||||
volatile float z;
|
volatile float z;
|
||||||
z = z * z;
|
z = z * z;
|
||||||
//CHECK: = fmul float
|
//CHECK-FENV: llvm.experimental.constrained.fmul{{.*}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: define {{.*}}myAdd{{.*}}
|
||||||
|
float myAdd(int i, float f) {
|
||||||
|
if (i<0)
|
||||||
|
return 1.0 + 2.0;
|
||||||
|
// Check that floating point constant folding doesn't occur if
|
||||||
|
// #pragma STC FENV_ACCESS is enabled.
|
||||||
|
//CHECK-FENV: llvm.experimental.constrained.fadd{{.*}}double 1.0{{.*}}double 2.0{{.*}}
|
||||||
|
//CHECK: store float 3.0{{.*}}retval{{.*}}
|
||||||
|
static double v = 1.0 / 3.0;
|
||||||
|
//CHECK-FENV: llvm.experimental.constrained.fptrunc.f32.f64{{.*}}
|
||||||
|
//CHECK-NOT: fdiv
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EXCEPT
|
#if EXCEPT
|
||||||
|
@ -201,3 +214,18 @@ float xx(double x, float z) {
|
||||||
return fc_template_namespace::exc_on<float>(x, z);
|
return fc_template_namespace::exc_on<float>(x, z);
|
||||||
}
|
}
|
||||||
#endif // EXCEPT
|
#endif // EXCEPT
|
||||||
|
|
||||||
|
float try_lam(float x, unsigned n) {
|
||||||
|
// CHECK: define {{.*}}try_lam{{.*}}class.anon{{.*}}
|
||||||
|
float result;
|
||||||
|
auto t =
|
||||||
|
// Lambda expression begins
|
||||||
|
[](float a, float b) {
|
||||||
|
#pragma float_control( except, on)
|
||||||
|
return a * b;
|
||||||
|
//CHECK: llvm.experimental.constrained.fmul{{.*}}fpexcept.strict
|
||||||
|
} // end of lambda expression
|
||||||
|
(1.0f,2.0f);
|
||||||
|
result = x + t;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
// RUN: %clang_cc1 -ffp-exception-behavior=strict -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS ON
|
||||||
|
|
||||||
|
float func_01(float x, float y) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_01
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
|
|
||||||
|
|
||||||
|
float func_02(float x, float y) {
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
#pragma STDC FENV_ACCESS OFF
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_02
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
||||||
|
|
||||||
|
|
||||||
|
float func_03(float x, float y) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_03
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
|
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS OFF
|
||||||
|
|
||||||
|
float func_04(float x, float y) {
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_04
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
||||||
|
|
||||||
|
|
||||||
|
float func_05(float x, float y) {
|
||||||
|
#pragma STDC FENV_ACCESS ON
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_05
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
|
|
||||||
|
|
||||||
|
float func_06(float x, float y) {
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_06
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
||||||
|
|
||||||
|
|
||||||
|
float func_07(float x, float y) {
|
||||||
|
x -= y;
|
||||||
|
if (x) {
|
||||||
|
#pragma STDC FENV_ACCESS ON
|
||||||
|
y *= 2;
|
||||||
|
}
|
||||||
|
return y + 4;
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: @func_07
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fsub.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
|
// CHECK: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
|
@ -26,19 +26,13 @@ void check_stack() {
|
||||||
double a = 0.0;
|
double a = 0.0;
|
||||||
double b = 1.0;
|
double b = 1.0;
|
||||||
|
|
||||||
//FIXME At some point this warning will be removed, until then
|
|
||||||
// document the warning
|
|
||||||
#ifdef FAST
|
|
||||||
// expected-warning@+1{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
|
|
||||||
#pragma STDC FENV_ACCESS ON
|
|
||||||
#else
|
|
||||||
#pragma STDC FENV_ACCESS ON // expected-warning{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
|
|
||||||
#endif
|
|
||||||
#ifdef STRICT
|
#ifdef STRICT
|
||||||
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
||||||
#else
|
#else
|
||||||
// Currently FENV_ACCESS cannot be enabled by pragma, skip error check
|
#ifndef FAST
|
||||||
#pragma float_control(precise, off) // not-expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}}
|
#pragma STDC FENV_ACCESS ON
|
||||||
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma float_control(precise, on)
|
#pragma float_control(precise, on)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||||
|
// RUN: %clang_cc1 -ffp-exception-behavior=strict -DSTRICT -fsyntax-only -verify %s
|
||||||
|
// RUN: %clang_cc1 -x c++ -DCPP -DSTRICT -ffp-exception-behavior=strict -fsyntax-only -verify %s
|
||||||
|
#ifdef CPP
|
||||||
|
#define CONST constexpr
|
||||||
|
#else
|
||||||
|
#define CONST const
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS OFF
|
||||||
|
|
||||||
|
float func_04(int x, float y) {
|
||||||
|
if (x)
|
||||||
|
return y + 2;
|
||||||
|
#pragma STDC FENV_ACCESS ON // expected-error{{'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of a compound statement}}
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma STDC FENV_ACCESS ON
|
||||||
|
int main() {
|
||||||
|
CONST float one = 1.0F ;
|
||||||
|
CONST float three = 3.0F ;
|
||||||
|
CONST float four = 4.0F ;
|
||||||
|
CONST float frac_ok = one/four;
|
||||||
|
#if !defined(CPP)
|
||||||
|
//expected-note@+2 {{declared here}}
|
||||||
|
#endif
|
||||||
|
CONST float frac = one/three;
|
||||||
|
CONST double d = one;
|
||||||
|
CONST int not_too_big = 255;
|
||||||
|
CONST float fnot_too_big = not_too_big;
|
||||||
|
CONST int too_big = 0x7ffffff0;
|
||||||
|
#if defined(CPP)
|
||||||
|
//expected-warning@+2{{implicit conversion}}
|
||||||
|
#endif
|
||||||
|
CONST float fbig = too_big; // inexact
|
||||||
|
#if !defined(CPP)
|
||||||
|
#define static_assert _Static_assert
|
||||||
|
#endif
|
||||||
|
enum {
|
||||||
|
e1 = (int)one, e3 = (int)three, e4 = (int)four, e_four_quarters = (int)(frac_ok * 4)
|
||||||
|
};
|
||||||
|
static_assert(e1 == 1 && e3 == 3 && e4 == 4 && e_four_quarters == 1, "");
|
||||||
|
enum {
|
||||||
|
#if !defined(CPP)
|
||||||
|
// expected-error@+2 {{not an integer constant expression}} expected-note@+2 {{is not a constant expression}}
|
||||||
|
#endif
|
||||||
|
e_three_thirds = (int)(frac * 3)
|
||||||
|
};
|
||||||
|
if (one <= four) return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -16,15 +16,6 @@
|
||||||
// CHECK: {{^}}#pragma STDC FP_CONTRACT DEFAULT{{$}}
|
// CHECK: {{^}}#pragma STDC FP_CONTRACT DEFAULT{{$}}
|
||||||
// CHECK: {{^}}#pragma STDC FP_CONTRACT IN_BETWEEN{{$}}
|
// CHECK: {{^}}#pragma STDC FP_CONTRACT IN_BETWEEN{{$}}
|
||||||
|
|
||||||
#pragma STDC FENV_ACCESS ON // expected-warning {{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
|
|
||||||
#pragma STDC FENV_ACCESS OFF
|
|
||||||
#pragma STDC FENV_ACCESS DEFAULT
|
|
||||||
#pragma STDC FENV_ACCESS IN_BETWEEN // expected-warning {{expected 'ON' or 'OFF' or 'DEFAULT' in pragma}}
|
|
||||||
// CHECK: {{^}}#pragma STDC FENV_ACCESS ON{{$}}
|
|
||||||
// CHECK: {{^}}#pragma STDC FENV_ACCESS OFF{{$}}
|
|
||||||
// CHECK: {{^}}#pragma STDC FENV_ACCESS DEFAULT{{$}}
|
|
||||||
// CHECK: {{^}}#pragma STDC FENV_ACCESS IN_BETWEEN{{$}}
|
|
||||||
|
|
||||||
#pragma STDC CX_LIMITED_RANGE ON
|
#pragma STDC CX_LIMITED_RANGE ON
|
||||||
#pragma STDC CX_LIMITED_RANGE OFF
|
#pragma STDC CX_LIMITED_RANGE OFF
|
||||||
#pragma STDC CX_LIMITED_RANGE DEFAULT
|
#pragma STDC CX_LIMITED_RANGE DEFAULT
|
||||||
|
|
Loading…
Reference in New Issue