forked from OSchip/llvm-project
Reapply "Add support for #pragma float_control" with buildbot fixes
Add support for #pragma float_control
Reviewers: rjmccall, erichkeane, sepavloff
Differential Revision: https://reviews.llvm.org/D72841
This reverts commit fce82c0ed3
.
This commit is contained in:
parent
67b466deda
commit
f5360d4bb3
clang
docs
include/clang
AST
Basic
DiagnosticParseKinds.tdDiagnosticSemaKinds.tdLangOptions.defLangOptions.hPragmaKinds.hTokenKinds.def
Parse
Sema
Serialization
lib
AST
Analysis
CodeGen
Frontend
Parse
Sema
Sema.cppSemaAttr.cppSemaDeclCXX.cppSemaExpr.cppSemaExprObjC.cppSemaOverload.cppSemaPseudoObject.cppSemaStmt.cpp
Serialization
test
llvm/include/llvm/IR
|
@ -3197,6 +3197,41 @@ The pragma can also be used with ``off`` which turns FP contraction off for a
|
||||||
section of the code. This can be useful when fast contraction is otherwise
|
section of the code. This can be useful when fast contraction is otherwise
|
||||||
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
|
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
|
||||||
|
|
||||||
|
The ``#pragma float_control`` pragma allows precise floating-point
|
||||||
|
semantics and floating-point exception behavior to be specified
|
||||||
|
for a section of the source code. This pragma can only appear at file scope or
|
||||||
|
at the start of a compound statement (excluding comments). When using within a
|
||||||
|
compound statement, the pragma is active within the scope of the compound
|
||||||
|
statement. This pragma is modeled after a Microsoft pragma with the
|
||||||
|
same spelling and syntax. For pragmas specified at file scope, a stack
|
||||||
|
is supported so that the ``pragma float_control`` settings can be pushed or popped.
|
||||||
|
|
||||||
|
When ``pragma float_control(precise, on)`` is enabled, the section of code
|
||||||
|
governed by the pragma uses precise floating point semantics, effectively
|
||||||
|
``-ffast-math`` is disabled and ``-ffp-contract=on``
|
||||||
|
(fused multiply add) is enabled.
|
||||||
|
|
||||||
|
When ``pragma float_control(except, on)`` is enabled, the section of code governed
|
||||||
|
by the pragma behaves as though the command-line option
|
||||||
|
``-ffp-exception-behavior=strict`` is enabled,
|
||||||
|
when ``pragma float_control(precise, off)`` is enabled, the section of code
|
||||||
|
governed by the pragma behaves as though the command-line option
|
||||||
|
``-ffp-exception-behavior=ignore`` is enabled.
|
||||||
|
|
||||||
|
The full syntax this pragma supports is
|
||||||
|
``float_control(except|precise, on|off [, push])`` and
|
||||||
|
``float_control(push|pop)``.
|
||||||
|
The ``push`` and ``pop`` forms, including using ``push`` as the optional
|
||||||
|
third argument, can only occur at file scope.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
for(...) {
|
||||||
|
// This block will be compiled with -fno-fast-math and -ffp-contract=on
|
||||||
|
#pragma float_control(precise, on)
|
||||||
|
a = b[i] * c[i] + e;
|
||||||
|
}
|
||||||
|
|
||||||
Specifying an attribute for multiple declarations (#pragma clang attribute)
|
Specifying an attribute for multiple declarations (#pragma clang attribute)
|
||||||
===========================================================================
|
===========================================================================
|
||||||
|
|
||||||
|
|
|
@ -2107,26 +2107,48 @@ public:
|
||||||
/// applied to a non-complex value, the former returns its operand and the
|
/// applied to a non-complex value, the former returns its operand and the
|
||||||
/// later returns zero in the type of the operand.
|
/// later returns zero in the type of the operand.
|
||||||
///
|
///
|
||||||
class UnaryOperator : public Expr {
|
class UnaryOperator final
|
||||||
|
: public Expr,
|
||||||
|
private llvm::TrailingObjects<UnaryOperator, FPOptions> {
|
||||||
Stmt *Val;
|
Stmt *Val;
|
||||||
|
|
||||||
|
size_t numTrailingObjects(OverloadToken<FPOptions>) const {
|
||||||
|
return UnaryOperatorBits.HasFPFeatures ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FPOptions &getTrailingFPFeatures() {
|
||||||
|
assert(UnaryOperatorBits.HasFPFeatures);
|
||||||
|
return *getTrailingObjects<FPOptions>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const FPOptions &getTrailingFPFeatures() const {
|
||||||
|
assert(UnaryOperatorBits.HasFPFeatures);
|
||||||
|
return *getTrailingObjects<FPOptions>();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef UnaryOperatorKind Opcode;
|
typedef UnaryOperatorKind Opcode;
|
||||||
|
|
||||||
UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK,
|
protected:
|
||||||
ExprObjectKind OK, SourceLocation l, bool CanOverflow)
|
UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc, QualType type,
|
||||||
: Expr(UnaryOperatorClass, type, VK, OK), Val(input) {
|
ExprValueKind VK, ExprObjectKind OK, SourceLocation l,
|
||||||
UnaryOperatorBits.Opc = opc;
|
bool CanOverflow, FPOptions FPFeatures);
|
||||||
UnaryOperatorBits.CanOverflow = CanOverflow;
|
|
||||||
UnaryOperatorBits.Loc = l;
|
|
||||||
setDependence(computeDependence(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build an empty unary operator.
|
/// Build an empty unary operator.
|
||||||
explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) {
|
explicit UnaryOperator(bool HasFPFeatures, EmptyShell Empty)
|
||||||
|
: Expr(UnaryOperatorClass, Empty) {
|
||||||
UnaryOperatorBits.Opc = UO_AddrOf;
|
UnaryOperatorBits.Opc = UO_AddrOf;
|
||||||
|
UnaryOperatorBits.HasFPFeatures = HasFPFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static UnaryOperator *CreateEmpty(const ASTContext &C, bool hasFPFeatures);
|
||||||
|
|
||||||
|
static UnaryOperator *Create(const ASTContext &C, Expr *input, Opcode opc,
|
||||||
|
QualType type, ExprValueKind VK,
|
||||||
|
ExprObjectKind OK, SourceLocation l,
|
||||||
|
bool CanOverflow, FPOptions FPFeatures);
|
||||||
|
|
||||||
Opcode getOpcode() const {
|
Opcode getOpcode() const {
|
||||||
return static_cast<Opcode>(UnaryOperatorBits.Opc);
|
return static_cast<Opcode>(UnaryOperatorBits.Opc);
|
||||||
}
|
}
|
||||||
|
@ -2148,6 +2170,18 @@ public:
|
||||||
bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
|
bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
|
||||||
void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; }
|
void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; }
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
/// isPostfix - Return true if this is a postfix operation, like x++.
|
/// isPostfix - Return true if this is a postfix operation, like x++.
|
||||||
static bool isPostfix(Opcode Op) {
|
static bool isPostfix(Opcode Op) {
|
||||||
return Op == UO_PostInc || Op == UO_PostDec;
|
return Op == UO_PostInc || Op == UO_PostDec;
|
||||||
|
@ -2214,6 +2248,30 @@ public:
|
||||||
const_child_range children() const {
|
const_child_range children() const {
|
||||||
return const_child_range(&Val, &Val + 1);
|
return const_child_range(&Val, &Val + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is FPFeatures in Trailing Storage?
|
||||||
|
bool hasStoredFPFeatures() const { return UnaryOperatorBits.HasFPFeatures; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Get FPFeatures from trailing storage
|
||||||
|
FPOptions getStoredFPFeatures() const { return getTrailingFPFeatures(); }
|
||||||
|
|
||||||
|
/// Set FPFeatures in trailing storage, used only by Serialization
|
||||||
|
void setStoredFPFeatures(FPOptions 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 {
|
||||||
|
if (UnaryOperatorBits.HasFPFeatures)
|
||||||
|
return getStoredFPFeatures();
|
||||||
|
return FPOptions::defaultWithoutTrailingStorage(LO);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend TrailingObjects;
|
||||||
|
friend class ASTReader;
|
||||||
|
friend class ASTStmtReader;
|
||||||
|
friend class ASTStmtWriter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper class for OffsetOfExpr.
|
/// Helper class for OffsetOfExpr.
|
||||||
|
|
|
@ -427,6 +427,11 @@ protected:
|
||||||
|
|
||||||
unsigned Opc : 5;
|
unsigned Opc : 5;
|
||||||
unsigned CanOverflow : 1;
|
unsigned CanOverflow : 1;
|
||||||
|
//
|
||||||
|
/// This is only meaningful for operations on floating point
|
||||||
|
/// types when additional values need to be in trailing storage.
|
||||||
|
/// It is 0 otherwise.
|
||||||
|
unsigned HasFPFeatures : 1;
|
||||||
|
|
||||||
SourceLocation Loc;
|
SourceLocation Loc;
|
||||||
};
|
};
|
||||||
|
@ -610,7 +615,7 @@ protected:
|
||||||
unsigned OperatorKind : 6;
|
unsigned OperatorKind : 6;
|
||||||
|
|
||||||
// Only meaningful for floating point types.
|
// Only meaningful for floating point types.
|
||||||
unsigned FPFeatures : 8;
|
unsigned FPFeatures : 14;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CXXRewrittenBinaryOperatorBitfields {
|
class CXXRewrittenBinaryOperatorBitfields {
|
||||||
|
|
|
@ -1097,9 +1097,9 @@ def warn_pragma_init_seg_unsupported_target : Warning<
|
||||||
"'#pragma init_seg' is only supported when targeting a "
|
"'#pragma init_seg' is only supported when targeting a "
|
||||||
"Microsoft environment">,
|
"Microsoft environment">,
|
||||||
InGroup<IgnoredPragmas>;
|
InGroup<IgnoredPragmas>;
|
||||||
// - #pragma fp_contract
|
// - #pragma restricted to file scope or start of compound statement
|
||||||
def err_pragma_fp_contract_scope : Error<
|
def err_pragma_file_or_compound_scope : Error<
|
||||||
"'#pragma fp_contract' can only appear at file scope or at the start of a "
|
"'#pragma %0' can only appear at file scope or at the start of a "
|
||||||
"compound statement">;
|
"compound statement">;
|
||||||
// - #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">,
|
||||||
|
@ -1118,6 +1118,10 @@ def warn_pragma_comment_ignored : Warning<"'#pragma comment %0' ignored">,
|
||||||
def err_pragma_detect_mismatch_malformed : Error<
|
def err_pragma_detect_mismatch_malformed : Error<
|
||||||
"pragma detect_mismatch is malformed; it requires two comma-separated "
|
"pragma detect_mismatch is malformed; it requires two comma-separated "
|
||||||
"string literals">;
|
"string literals">;
|
||||||
|
// - #pragma float_control
|
||||||
|
def err_pragma_float_control_malformed : Error<
|
||||||
|
"pragma float_control is malformed; use 'float_control({push|pop})' or "
|
||||||
|
"'float_control({precise|except}, {on|off} [,push])'">;
|
||||||
// - #pragma pointers_to_members
|
// - #pragma pointers_to_members
|
||||||
def err_pragma_pointers_to_members_unknown_kind : Error<
|
def err_pragma_pointers_to_members_unknown_kind : Error<
|
||||||
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
|
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
|
||||||
|
@ -1332,9 +1336,6 @@ def err_pragma_fp_invalid_option : Error<
|
||||||
def err_pragma_fp_invalid_argument : Error<
|
def err_pragma_fp_invalid_argument : Error<
|
||||||
"unexpected argument '%0' to '#pragma clang fp %1'; "
|
"unexpected argument '%0' to '#pragma clang fp %1'; "
|
||||||
"expected 'on', 'fast' or 'off'">;
|
"expected 'on', 'fast' or 'off'">;
|
||||||
def err_pragma_fp_scope : Error<
|
|
||||||
"'#pragma clang fp' can only appear at file scope or at the start of a "
|
|
||||||
"compound statement">;
|
|
||||||
|
|
||||||
def err_pragma_invalid_keyword : Error<
|
def err_pragma_invalid_keyword : Error<
|
||||||
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
|
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
|
||||||
|
|
|
@ -858,6 +858,16 @@ def warn_pragma_pack_pop_identifier_and_alignment : Warning<
|
||||||
"specifying both a name and alignment to 'pop' is undefined">;
|
"specifying both a name and alignment to 'pop' is undefined">;
|
||||||
def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
|
def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">,
|
||||||
InGroup<IgnoredPragmas>;
|
InGroup<IgnoredPragmas>;
|
||||||
|
def err_pragma_fc_pp_scope : Error<
|
||||||
|
"'#pragma float_control push/pop' can only appear at file scope">;
|
||||||
|
def err_pragma_fc_noprecise_requires_nofenv : Error<
|
||||||
|
"'#pragma float_control(precise, off)' is illegal when fenv_access is enabled">;
|
||||||
|
def err_pragma_fc_except_requires_precise : Error<
|
||||||
|
"'#pragma float_control(except, on)' is illegal when precise is disabled">;
|
||||||
|
def err_pragma_fc_noprecise_requires_noexcept : Error<
|
||||||
|
"'#pragma float_control(precise, off)' is illegal when except is enabled">;
|
||||||
|
def err_pragma_fenv_requires_precise : Error<
|
||||||
|
"'#pragma STDC FENV_ACCESS ON' is illegal when precise is disabled">;
|
||||||
def warn_cxx_ms_struct :
|
def warn_cxx_ms_struct :
|
||||||
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
|
Warning<"ms_struct may not produce Microsoft-compatible layouts for classes "
|
||||||
"with base classes or virtual functions">,
|
"with base classes or virtual functions">,
|
||||||
|
|
|
@ -191,6 +191,12 @@ COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro")
|
||||||
COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro")
|
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(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro")
|
||||||
COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math")
|
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(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
|
BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars")
|
||||||
|
|
||||||
|
|
|
@ -377,28 +377,33 @@ class FPOptions {
|
||||||
using RoundingMode = llvm::RoundingMode;
|
using RoundingMode = llvm::RoundingMode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FPOptions() : fp_contract(LangOptions::FPC_Off),
|
FPOptions()
|
||||||
fenv_access(LangOptions::FEA_Off),
|
: fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off),
|
||||||
rounding(LangOptions::FPR_ToNearest),
|
rounding(LangOptions::FPR_ToNearest),
|
||||||
exceptions(LangOptions::FPE_Ignore)
|
exceptions(LangOptions::FPE_Ignore), allow_reassoc(0), no_nans(0),
|
||||||
{}
|
no_infs(0), no_signed_zeros(0), allow_reciprocal(0), approx_func(0) {}
|
||||||
|
|
||||||
// Used for serializing.
|
// Used for serializing.
|
||||||
explicit FPOptions(unsigned I)
|
explicit FPOptions(unsigned I) { getFromOpaqueInt(I); }
|
||||||
: fp_contract(I & 3),
|
|
||||||
fenv_access((I >> 2) & 1),
|
|
||||||
rounding ((I >> 3) & 7),
|
|
||||||
exceptions ((I >> 6) & 3)
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit FPOptions(const LangOptions &LangOpts)
|
explicit FPOptions(const LangOptions &LangOpts)
|
||||||
: fp_contract(LangOpts.getDefaultFPContractMode()),
|
: fp_contract(LangOpts.getDefaultFPContractMode()),
|
||||||
fenv_access(LangOptions::FEA_Off),
|
fenv_access(LangOptions::FEA_Off),
|
||||||
rounding(LangOptions::FPR_ToNearest),
|
rounding(static_cast<unsigned>(LangOpts.getFPRoundingMode())),
|
||||||
exceptions(LangOptions::FPE_Ignore)
|
exceptions(LangOpts.getFPExceptionMode()),
|
||||||
{}
|
allow_reassoc(LangOpts.FastMath || LangOpts.AllowFPReassoc),
|
||||||
|
no_nans(LangOpts.FastMath || LangOpts.NoHonorNaNs),
|
||||||
|
no_infs(LangOpts.FastMath || LangOpts.NoHonorInfs),
|
||||||
|
no_signed_zeros(LangOpts.FastMath || LangOpts.NoSignedZero),
|
||||||
|
allow_reciprocal(LangOpts.FastMath || LangOpts.AllowRecip),
|
||||||
|
approx_func(LangOpts.FastMath || LangOpts.ApproxFunc) {}
|
||||||
// FIXME: Use getDefaultFEnvAccessMode() when available.
|
// FIXME: Use getDefaultFEnvAccessMode() when available.
|
||||||
|
|
||||||
|
void setFastMath(bool B = true) {
|
||||||
|
allow_reassoc = no_nans = no_infs = no_signed_zeros = approx_func =
|
||||||
|
allow_reciprocal = B;
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the default value of FPOptions that's used when trailing
|
/// Return the default value of FPOptions that's used when trailing
|
||||||
/// storage isn't required.
|
/// storage isn't required.
|
||||||
static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
|
static FPOptions defaultWithoutTrailingStorage(const LangOptions &LO);
|
||||||
|
@ -433,6 +438,18 @@ public:
|
||||||
fenv_access = LangOptions::FEA_On;
|
fenv_access = LangOptions::FEA_On;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
|
void setDisallowFEnvAccess() { fenv_access = LangOptions::FEA_Off; }
|
||||||
|
|
||||||
RoundingMode getRoundingMode() const {
|
RoundingMode getRoundingMode() const {
|
||||||
|
@ -451,6 +468,22 @@ public:
|
||||||
exceptions = EM;
|
exceptions = EM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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; }
|
||||||
|
|
||||||
bool isFPConstrained() const {
|
bool isFPConstrained() const {
|
||||||
return getRoundingMode() != RoundingMode::NearestTiesToEven ||
|
return getRoundingMode() != RoundingMode::NearestTiesToEven ||
|
||||||
getExceptionMode() != LangOptions::FPE_Ignore ||
|
getExceptionMode() != LangOptions::FPE_Ignore ||
|
||||||
|
@ -460,7 +493,23 @@ public:
|
||||||
/// Used to serialize this.
|
/// Used to serialize this.
|
||||||
unsigned getAsOpaqueInt() const {
|
unsigned getAsOpaqueInt() const {
|
||||||
return fp_contract | (fenv_access << 2) | (rounding << 3) |
|
return fp_contract | (fenv_access << 2) | (rounding << 3) |
|
||||||
(exceptions << 6);
|
(exceptions << 6) | (allow_reassoc << 8) | (no_nans << 9) |
|
||||||
|
(no_infs << 10) | (no_signed_zeros << 11) |
|
||||||
|
(allow_reciprocal << 12) | (approx_func << 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used with getAsOpaqueInt() to manage the float_control pragma stack.
|
||||||
|
void getFromOpaqueInt(unsigned I) {
|
||||||
|
fp_contract = (static_cast<LangOptions::FPContractModeKind>(I & 3));
|
||||||
|
fenv_access = (static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1));
|
||||||
|
rounding = static_cast<unsigned>(static_cast<RoundingMode>((I >> 3) & 7));
|
||||||
|
exceptions = (static_cast<LangOptions::FPExceptionModeKind>((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);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -471,6 +520,25 @@ private:
|
||||||
unsigned fenv_access : 1;
|
unsigned fenv_access : 1;
|
||||||
unsigned rounding : 3;
|
unsigned rounding : 3;
|
||||||
unsigned exceptions : 2;
|
unsigned exceptions : 2;
|
||||||
|
/// Allow reassociation transformations for floating-point instructions.
|
||||||
|
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 <poisonvalues>` 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 <poisonvalues>` 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Describes the kind of translation unit being processed.
|
/// Describes the kind of translation unit being processed.
|
||||||
|
|
|
@ -25,6 +25,15 @@ enum PragmaMSStructKind {
|
||||||
PMSST_ON // #pragms ms_struct on
|
PMSST_ON // #pragms ms_struct on
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PragmaFloatControlKind {
|
||||||
|
PFC_Unknown,
|
||||||
|
PFC_Precise, // #pragma float_control(precise, [,on])
|
||||||
|
PFC_NoPrecise, // #pragma float_control(precise, off)
|
||||||
|
PFC_Except, // #pragma float_control(except [,on])
|
||||||
|
PFC_NoExcept, // #pragma float_control(except, off)
|
||||||
|
PFC_Push, // #pragma float_control(push)
|
||||||
|
PFC_Pop // #pragma float_control(pop)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -809,6 +809,11 @@ PRAGMA_ANNOTATION(pragma_fp_contract)
|
||||||
// handles them.
|
// handles them.
|
||||||
PRAGMA_ANNOTATION(pragma_fenv_access)
|
PRAGMA_ANNOTATION(pragma_fenv_access)
|
||||||
|
|
||||||
|
// Annotation for #pragma float_control
|
||||||
|
// The lexer produces these so that they only take effect when the parser
|
||||||
|
// handles them.
|
||||||
|
PRAGMA_ANNOTATION(pragma_float_control)
|
||||||
|
|
||||||
// Annotation for #pragma pointers_to_members...
|
// Annotation for #pragma pointers_to_members...
|
||||||
// The lexer produces these so that they only take effect when the parser
|
// The lexer produces these so that they only take effect when the parser
|
||||||
// handles them.
|
// handles them.
|
||||||
|
|
|
@ -182,6 +182,7 @@ class Parser : public CodeCompletionHandler {
|
||||||
std::unique_ptr<PragmaHandler> PCSectionHandler;
|
std::unique_ptr<PragmaHandler> PCSectionHandler;
|
||||||
std::unique_ptr<PragmaHandler> MSCommentHandler;
|
std::unique_ptr<PragmaHandler> MSCommentHandler;
|
||||||
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
|
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
|
||||||
|
std::unique_ptr<PragmaHandler> FloatControlHandler;
|
||||||
std::unique_ptr<PragmaHandler> MSPointersToMembers;
|
std::unique_ptr<PragmaHandler> MSPointersToMembers;
|
||||||
std::unique_ptr<PragmaHandler> MSVtorDisp;
|
std::unique_ptr<PragmaHandler> MSVtorDisp;
|
||||||
std::unique_ptr<PragmaHandler> MSInitSeg;
|
std::unique_ptr<PragmaHandler> MSInitSeg;
|
||||||
|
@ -741,6 +742,10 @@ private:
|
||||||
/// #pragma STDC FENV_ACCESS...
|
/// #pragma STDC FENV_ACCESS...
|
||||||
void HandlePragmaFEnvAccess();
|
void HandlePragmaFEnvAccess();
|
||||||
|
|
||||||
|
/// Handle the annotation token produced for
|
||||||
|
/// #pragma float_control
|
||||||
|
void HandlePragmaFloatControl();
|
||||||
|
|
||||||
/// \brief Handle the annotation token produced for
|
/// \brief Handle the annotation token produced for
|
||||||
/// #pragma clang fp ...
|
/// #pragma clang fp ...
|
||||||
void HandlePragmaFP();
|
void HandlePragmaFP();
|
||||||
|
|
|
@ -555,6 +555,9 @@ public:
|
||||||
PragmaStack<StringLiteral *> ConstSegStack;
|
PragmaStack<StringLiteral *> ConstSegStack;
|
||||||
PragmaStack<StringLiteral *> CodeSegStack;
|
PragmaStack<StringLiteral *> CodeSegStack;
|
||||||
|
|
||||||
|
// This stack tracks the current state of Sema.CurFPFeatures.
|
||||||
|
PragmaStack<unsigned> FpPragmaStack;
|
||||||
|
|
||||||
// RAII object to push / pop sentinel slots for all MS #pragma stacks.
|
// 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.
|
// Actions should be performed only if we enter / exit a C++ method body.
|
||||||
class PragmaStackSentinelRAII {
|
class PragmaStackSentinelRAII {
|
||||||
|
@ -1350,7 +1353,7 @@ public:
|
||||||
/// should not be used elsewhere.
|
/// should not be used elsewhere.
|
||||||
void EmitCurrentDiagnostic(unsigned DiagID);
|
void EmitCurrentDiagnostic(unsigned DiagID);
|
||||||
|
|
||||||
/// Records and restores the FPFeatures state on entry/exit of compound
|
/// Records and restores the CurFPFeatures state on entry/exit of compound
|
||||||
/// statements.
|
/// statements.
|
||||||
class FPFeaturesStateRAII {
|
class FPFeaturesStateRAII {
|
||||||
public:
|
public:
|
||||||
|
@ -9566,6 +9569,18 @@ public:
|
||||||
void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
|
void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
|
||||||
StringRef Value);
|
StringRef Value);
|
||||||
|
|
||||||
|
/// Are precise floating point semantics currently enabled?
|
||||||
|
bool isPreciseFPEnabled() {
|
||||||
|
return !CurFPFeatures.allowAssociativeMath() &&
|
||||||
|
!CurFPFeatures.noSignedZeros() &&
|
||||||
|
!CurFPFeatures.allowReciprocalMath() &&
|
||||||
|
!CurFPFeatures.allowApproximateFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ActOnPragmaFloatControl - Call on well-formed \#pragma float_control
|
||||||
|
void ActOnPragmaFloatControl(SourceLocation Loc, PragmaMsStackAction Action,
|
||||||
|
PragmaFloatControlKind Value);
|
||||||
|
|
||||||
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
|
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
|
||||||
void ActOnPragmaUnused(const Token &Identifier,
|
void ActOnPragmaUnused(const Token &Identifier,
|
||||||
Scope *curScope,
|
Scope *curScope,
|
||||||
|
@ -9606,7 +9621,8 @@ public:
|
||||||
|
|
||||||
/// ActOnPragmaFenvAccess - Called on well formed
|
/// ActOnPragmaFenvAccess - Called on well formed
|
||||||
/// \#pragma STDC FENV_ACCESS
|
/// \#pragma STDC FENV_ACCESS
|
||||||
void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC);
|
void ActOnPragmaFEnvAccess(SourceLocation Loc,
|
||||||
|
LangOptions::FEnvAccessModeKind FPC);
|
||||||
|
|
||||||
/// Called to set rounding mode for floating point operations.
|
/// Called to set rounding mode for floating point operations.
|
||||||
void setRoundingMode(llvm::RoundingMode);
|
void setRoundingMode(llvm::RoundingMode);
|
||||||
|
|
|
@ -686,6 +686,9 @@ namespace serialization {
|
||||||
|
|
||||||
/// Record code for the Decls to be checked for deferred diags.
|
/// Record code for the Decls to be checked for deferred diags.
|
||||||
DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64,
|
DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64,
|
||||||
|
|
||||||
|
/// Record code for \#pragma float_control options.
|
||||||
|
FLOAT_CONTROL_PRAGMA_OPTIONS = 65,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Record types used within a source manager block.
|
/// Record types used within a source manager block.
|
||||||
|
|
|
@ -857,6 +857,18 @@ private:
|
||||||
int PragmaMSPointersToMembersState = -1;
|
int PragmaMSPointersToMembersState = -1;
|
||||||
SourceLocation PointersToMembersPragmaLocation;
|
SourceLocation PointersToMembersPragmaLocation;
|
||||||
|
|
||||||
|
/// The pragma float_control state.
|
||||||
|
Optional<unsigned> FpPragmaCurrentValue;
|
||||||
|
SourceLocation FpPragmaCurrentLocation;
|
||||||
|
struct FpPragmaStackEntry {
|
||||||
|
unsigned Value;
|
||||||
|
SourceLocation Location;
|
||||||
|
SourceLocation PushLocation;
|
||||||
|
StringRef SlotLabel;
|
||||||
|
};
|
||||||
|
llvm::SmallVector<FpPragmaStackEntry, 2> FpPragmaStack;
|
||||||
|
llvm::SmallVector<std::string, 2> FpPragmaStrings;
|
||||||
|
|
||||||
/// The pragma pack state.
|
/// The pragma pack state.
|
||||||
Optional<unsigned> PragmaPackCurrentValue;
|
Optional<unsigned> PragmaPackCurrentValue;
|
||||||
SourceLocation PragmaPackCurrentLocation;
|
SourceLocation PragmaPackCurrentLocation;
|
||||||
|
|
|
@ -505,6 +505,7 @@ private:
|
||||||
void WriteMSStructPragmaOptions(Sema &SemaRef);
|
void WriteMSStructPragmaOptions(Sema &SemaRef);
|
||||||
void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
|
void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
|
||||||
void WritePackPragmaOptions(Sema &SemaRef);
|
void WritePackPragmaOptions(Sema &SemaRef);
|
||||||
|
void WriteFloatControlPragmaOptions(Sema &SemaRef);
|
||||||
void WriteModuleFileExtension(Sema &SemaRef,
|
void WriteModuleFileExtension(Sema &SemaRef,
|
||||||
ModuleFileExtensionWriter &Writer);
|
ModuleFileExtensionWriter &Writer);
|
||||||
|
|
||||||
|
|
|
@ -6660,9 +6660,10 @@ ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
|
||||||
if (Err)
|
if (Err)
|
||||||
return std::move(Err);
|
return std::move(Err);
|
||||||
|
|
||||||
return new (Importer.getToContext()) UnaryOperator(
|
return UnaryOperator::Create(
|
||||||
ToSubExpr, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(),
|
Importer.getToContext(), ToSubExpr, E->getOpcode(), ToType,
|
||||||
ToOperatorLoc, E->canOverflow());
|
E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow(),
|
||||||
|
E->getFPFeatures(Importer.getFromContext().getLangOpts()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpectedStmt
|
ExpectedStmt
|
||||||
|
|
|
@ -1358,7 +1358,8 @@ CallExpr *CallExpr::CreateTemporary(void *Mem, Expr *Fn, QualType Ty,
|
||||||
assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) &&
|
assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) &&
|
||||||
"Misaligned memory in CallExpr::CreateTemporary!");
|
"Misaligned memory in CallExpr::CreateTemporary!");
|
||||||
return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty,
|
return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty,
|
||||||
VK, RParenLoc, /*MinNumArgs=*/0, UsesADL);
|
VK, RParenLoc,
|
||||||
|
/*MinNumArgs=*/0, UsesADL);
|
||||||
}
|
}
|
||||||
|
|
||||||
CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
|
CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
|
||||||
|
@ -4445,6 +4446,38 @@ CompoundAssignOperator *CompoundAssignOperator::Create(
|
||||||
CompLHSType, CompResultType);
|
CompLHSType, CompResultType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnaryOperator *UnaryOperator::CreateEmpty(const ASTContext &C,
|
||||||
|
bool hasFPFeatures) {
|
||||||
|
void *Mem = C.Allocate(totalSizeToAlloc<FPOptions>(hasFPFeatures),
|
||||||
|
alignof(UnaryOperator));
|
||||||
|
return new (Mem) UnaryOperator(hasFPFeatures, EmptyShell());
|
||||||
|
}
|
||||||
|
|
||||||
|
UnaryOperator::UnaryOperator(const ASTContext &Ctx, Expr *input, Opcode opc,
|
||||||
|
QualType type, ExprValueKind VK, ExprObjectKind OK,
|
||||||
|
SourceLocation l, bool CanOverflow,
|
||||||
|
FPOptions FPFeatures)
|
||||||
|
: Expr(UnaryOperatorClass, type, VK, OK), Val(input) {
|
||||||
|
UnaryOperatorBits.Opc = opc;
|
||||||
|
UnaryOperatorBits.CanOverflow = CanOverflow;
|
||||||
|
UnaryOperatorBits.Loc = l;
|
||||||
|
UnaryOperatorBits.HasFPFeatures =
|
||||||
|
FPFeatures.requiresTrailingStorage(Ctx.getLangOpts());
|
||||||
|
setDependence(computeDependence(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
UnaryOperator *UnaryOperator::Create(const ASTContext &C, Expr *input,
|
||||||
|
Opcode opc, QualType type,
|
||||||
|
ExprValueKind VK, ExprObjectKind OK,
|
||||||
|
SourceLocation l, bool CanOverflow,
|
||||||
|
FPOptions FPFeatures) {
|
||||||
|
bool HasFPFeatures = FPFeatures.requiresTrailingStorage(C.getLangOpts());
|
||||||
|
unsigned Size = totalSizeToAlloc<FPOptions>(HasFPFeatures);
|
||||||
|
void *Mem = C.Allocate(Size, alignof(UnaryOperator));
|
||||||
|
return new (Mem)
|
||||||
|
UnaryOperator(C, input, opc, type, VK, OK, l, CanOverflow, FPFeatures);
|
||||||
|
}
|
||||||
|
|
||||||
const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
|
const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
|
||||||
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
|
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
|
||||||
e = ewc->getSubExpr();
|
e = ewc->getSubExpr();
|
||||||
|
|
|
@ -146,9 +146,10 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(
|
||||||
}
|
}
|
||||||
|
|
||||||
UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
|
UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
|
||||||
return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
|
return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
|
||||||
VK_LValue, OK_Ordinary, SourceLocation(),
|
VK_LValue, OK_Ordinary, SourceLocation(),
|
||||||
/*CanOverflow*/ false);
|
/*CanOverflow*/ false,
|
||||||
|
FPOptions(C.getLangOpts()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
|
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
|
||||||
|
@ -447,15 +448,16 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
|
||||||
QualType DerefType = Deref->getType();
|
QualType DerefType = Deref->getType();
|
||||||
|
|
||||||
// Negation predicate.
|
// Negation predicate.
|
||||||
UnaryOperator *FlagCheck = new (C) UnaryOperator(
|
UnaryOperator *FlagCheck = UnaryOperator::Create(
|
||||||
|
C,
|
||||||
/* input=*/
|
/* input=*/
|
||||||
M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
|
M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
|
||||||
CK_IntegralToBoolean),
|
CK_IntegralToBoolean),
|
||||||
/* opc=*/ UO_LNot,
|
/* opc=*/UO_LNot,
|
||||||
/* QualType=*/ C.IntTy,
|
/* QualType=*/C.IntTy,
|
||||||
/* ExprValueKind=*/ VK_RValue,
|
/* ExprValueKind=*/VK_RValue,
|
||||||
/* ExprObjectKind=*/ OK_Ordinary, SourceLocation(),
|
/* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
|
||||||
/* CanOverflow*/ false);
|
/* CanOverflow*/ false, FPOptions(C.getLangOpts()));
|
||||||
|
|
||||||
// Create assignment.
|
// Create assignment.
|
||||||
BinaryOperator *FlagAssignment = M.makeAssignment(
|
BinaryOperator *FlagAssignment = M.makeAssignment(
|
||||||
|
@ -518,9 +520,9 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
|
||||||
|
|
||||||
// (2) Create the assignment to the predicate.
|
// (2) Create the assignment to the predicate.
|
||||||
Expr *DoneValue =
|
Expr *DoneValue =
|
||||||
new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy,
|
UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
|
||||||
VK_RValue, OK_Ordinary, SourceLocation(),
|
C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(),
|
||||||
/*CanOverflow*/false);
|
/*CanOverflow*/ false, FPOptions(C.getLangOpts()));
|
||||||
|
|
||||||
BinaryOperator *B =
|
BinaryOperator *B =
|
||||||
M.makeAssignment(
|
M.makeAssignment(
|
||||||
|
|
|
@ -217,7 +217,14 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
|
||||||
/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
|
/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
|
||||||
static void updateFastMathFlags(llvm::FastMathFlags &FMF,
|
static void updateFastMathFlags(llvm::FastMathFlags &FMF,
|
||||||
FPOptions FPFeatures) {
|
FPOptions FPFeatures) {
|
||||||
FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement());
|
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.setAllowContract(FPFeatures.allowFPContractAcrossStatement() ||
|
||||||
|
FPFeatures.allowFPContractWithinStatement());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Propagate fast-math flags from \p Op to the instruction in \p V.
|
/// Propagate fast-math flags from \p Op to the instruction in \p V.
|
||||||
|
@ -230,6 +237,25 @@ static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
|
||||||
return V;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setBuilderFlagsFromFPFeatures(CGBuilderTy &Builder,
|
||||||
|
CodeGenFunction &CGF,
|
||||||
|
FPOptions FPFeatures) {
|
||||||
|
auto NewRoundingBehavior = FPFeatures.getRoundingMode();
|
||||||
|
Builder.setDefaultConstrainedRounding(NewRoundingBehavior);
|
||||||
|
auto NewExceptionBehavior =
|
||||||
|
ToConstrainedExceptMD(FPFeatures.getExceptionMode());
|
||||||
|
Builder.setDefaultConstrainedExcept(NewExceptionBehavior);
|
||||||
|
auto FMF = Builder.getFastMathFlags();
|
||||||
|
updateFastMathFlags(FMF, FPFeatures);
|
||||||
|
Builder.setFastMathFlags(FMF);
|
||||||
|
assert((CGF.CurFuncDecl == nullptr || Builder.getIsFPConstrained() ||
|
||||||
|
isa<CXXConstructorDecl>(CGF.CurFuncDecl) ||
|
||||||
|
isa<CXXDestructorDecl>(CGF.CurFuncDecl) ||
|
||||||
|
(NewExceptionBehavior == llvm::fp::ebIgnore &&
|
||||||
|
NewRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) &&
|
||||||
|
"FPConstrained should be enabled on entire function");
|
||||||
|
}
|
||||||
|
|
||||||
class ScalarExprEmitter
|
class ScalarExprEmitter
|
||||||
: public StmtVisitor<ScalarExprEmitter, Value*> {
|
: public StmtVisitor<ScalarExprEmitter, Value*> {
|
||||||
CodeGenFunction &CGF;
|
CodeGenFunction &CGF;
|
||||||
|
@ -744,6 +770,9 @@ public:
|
||||||
return EmitOverflowCheckedBinOp(Ops);
|
return EmitOverflowCheckedBinOp(Ops);
|
||||||
|
|
||||||
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
|
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
|
// Preserve the old values
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF, Ops.FPFeatures);
|
||||||
Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
|
Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
|
||||||
return propagateFMFlags(V, Ops);
|
return propagateFMFlags(V, Ops);
|
||||||
}
|
}
|
||||||
|
@ -2333,13 +2362,14 @@ Value *ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E,
|
static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E,
|
||||||
llvm::Value *InVal, bool IsInc) {
|
llvm::Value *InVal, bool IsInc,
|
||||||
|
FPOptions FPFeatures) {
|
||||||
BinOpInfo BinOp;
|
BinOpInfo BinOp;
|
||||||
BinOp.LHS = InVal;
|
BinOp.LHS = InVal;
|
||||||
BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
|
BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
|
||||||
BinOp.Ty = E->getType();
|
BinOp.Ty = E->getType();
|
||||||
BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
|
BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
|
||||||
// FIXME: once UnaryOperator carries FPFeatures, copy it here.
|
BinOp.FPFeatures = FPFeatures;
|
||||||
BinOp.E = E;
|
BinOp.E = E;
|
||||||
return BinOp;
|
return BinOp;
|
||||||
}
|
}
|
||||||
|
@ -2359,7 +2389,8 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
|
||||||
case LangOptions::SOB_Trapping:
|
case LangOptions::SOB_Trapping:
|
||||||
if (!E->canOverflow())
|
if (!E->canOverflow())
|
||||||
return Builder.CreateNSWAdd(InVal, Amount, Name);
|
return Builder.CreateNSWAdd(InVal, Amount, Name);
|
||||||
return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc));
|
return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
|
||||||
|
E, InVal, IsInc, E->getFPFeatures(CGF.getLangOpts())));
|
||||||
}
|
}
|
||||||
llvm_unreachable("Unknown SignedOverflowBehaviorTy");
|
llvm_unreachable("Unknown SignedOverflowBehaviorTy");
|
||||||
}
|
}
|
||||||
|
@ -2505,8 +2536,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||||
value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
|
value = EmitIncDecConsiderOverflowBehavior(E, value, isInc);
|
||||||
} else if (E->canOverflow() && type->isUnsignedIntegerType() &&
|
} else if (E->canOverflow() && type->isUnsignedIntegerType() &&
|
||||||
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
|
CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) {
|
||||||
value =
|
value = EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(
|
||||||
EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, value, isInc));
|
E, value, isInc, E->getFPFeatures(CGF.getLangOpts())));
|
||||||
} else {
|
} else {
|
||||||
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
|
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true);
|
||||||
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
|
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
|
||||||
|
@ -2706,7 +2737,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
|
||||||
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
|
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
|
||||||
BinOp.Ty = E->getType();
|
BinOp.Ty = E->getType();
|
||||||
BinOp.Opcode = BO_Sub;
|
BinOp.Opcode = BO_Sub;
|
||||||
// FIXME: once UnaryOperator carries FPFeatures, copy it here.
|
BinOp.FPFeatures = E->getFPFeatures(CGF.getLangOpts());
|
||||||
BinOp.E = E;
|
BinOp.E = E;
|
||||||
return EmitSub(BinOp);
|
return EmitSub(BinOp);
|
||||||
}
|
}
|
||||||
|
@ -2723,9 +2754,12 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
|
||||||
Value *Oper = Visit(E->getSubExpr());
|
Value *Oper = Visit(E->getSubExpr());
|
||||||
Value *Zero = llvm::Constant::getNullValue(Oper->getType());
|
Value *Zero = llvm::Constant::getNullValue(Oper->getType());
|
||||||
Value *Result;
|
Value *Result;
|
||||||
if (Oper->getType()->isFPOrFPVectorTy())
|
if (Oper->getType()->isFPOrFPVectorTy()) {
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF,
|
||||||
|
E->getFPFeatures(CGF.getLangOpts()));
|
||||||
Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp");
|
Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp");
|
||||||
else
|
} else
|
||||||
Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
|
Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
|
||||||
return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
|
return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
|
||||||
}
|
}
|
||||||
|
@ -3134,7 +3168,10 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
|
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
|
llvm::Value *Val;
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF, Ops.FPFeatures);
|
||||||
|
Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
|
||||||
if (CGF.getLangOpts().OpenCL &&
|
if (CGF.getLangOpts().OpenCL &&
|
||||||
!CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) {
|
!CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) {
|
||||||
// OpenCL v1.1 s7.4: minimum accuracy of single precision / is 2.5ulp
|
// OpenCL v1.1 s7.4: minimum accuracy of single precision / is 2.5ulp
|
||||||
|
@ -3506,6 +3543,8 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
|
||||||
return EmitOverflowCheckedBinOp(op);
|
return EmitOverflowCheckedBinOp(op);
|
||||||
|
|
||||||
if (op.LHS->getType()->isFPOrFPVectorTy()) {
|
if (op.LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures);
|
||||||
// Try to form an fmuladd.
|
// Try to form an fmuladd.
|
||||||
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
|
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
|
||||||
return FMulAdd;
|
return FMulAdd;
|
||||||
|
@ -3688,6 +3727,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
|
||||||
return EmitOverflowCheckedBinOp(op);
|
return EmitOverflowCheckedBinOp(op);
|
||||||
|
|
||||||
if (op.LHS->getType()->isFPOrFPVectorTy()) {
|
if (op.LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures);
|
||||||
// Try to form an fmuladd.
|
// Try to form an fmuladd.
|
||||||
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
|
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
|
||||||
return FMulAdd;
|
return FMulAdd;
|
||||||
|
@ -4014,6 +4055,8 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
|
||||||
if (BOInfo.isFixedPointOp()) {
|
if (BOInfo.isFixedPointOp()) {
|
||||||
Result = EmitFixedPointBinOp(BOInfo);
|
Result = EmitFixedPointBinOp(BOInfo);
|
||||||
} else if (LHS->getType()->isFPOrFPVectorTy()) {
|
} else if (LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF, BOInfo.FPFeatures);
|
||||||
if (!IsSignaling)
|
if (!IsSignaling)
|
||||||
Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
|
Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp");
|
||||||
else
|
else
|
||||||
|
@ -4166,6 +4209,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
|
||||||
Value *RHS = Visit(E->getRHS());
|
Value *RHS = Visit(E->getRHS());
|
||||||
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
|
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
|
||||||
if (LHS->getType()->isFPOrFPVectorTy()) {
|
if (LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF,
|
||||||
|
E->getFPFeatures(CGF.getLangOpts()));
|
||||||
LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
|
LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
|
||||||
RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
|
RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
|
||||||
} else {
|
} else {
|
||||||
|
@ -4250,6 +4296,9 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
|
||||||
Value *RHS = Visit(E->getRHS());
|
Value *RHS = Visit(E->getRHS());
|
||||||
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
|
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
|
||||||
if (LHS->getType()->isFPOrFPVectorTy()) {
|
if (LHS->getType()->isFPOrFPVectorTy()) {
|
||||||
|
llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder);
|
||||||
|
setBuilderFlagsFromFPFeatures(Builder, CGF,
|
||||||
|
E->getFPFeatures(CGF.getLangOpts()));
|
||||||
LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
|
LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
|
||||||
RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
|
RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3556,17 +3556,17 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
|
||||||
|
|
||||||
StartFunction(FD, ReturnTy, Fn, FI, args);
|
StartFunction(FD, ReturnTy, Fn, FI, args);
|
||||||
|
|
||||||
DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue,
|
DeclRefExpr DstExpr(C, &DstDecl, false, DestTy, VK_RValue, SourceLocation());
|
||||||
SourceLocation());
|
UnaryOperator *DST = UnaryOperator::Create(
|
||||||
UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
|
C, &DstExpr, UO_Deref, DestTy->getPointeeType(), VK_LValue, OK_Ordinary,
|
||||||
VK_LValue, OK_Ordinary, SourceLocation(), false);
|
SourceLocation(), false, FPOptions(C.getLangOpts()));
|
||||||
|
|
||||||
DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
|
DeclRefExpr SrcExpr(C, &SrcDecl, false, SrcTy, VK_RValue, SourceLocation());
|
||||||
SourceLocation());
|
UnaryOperator *SRC = UnaryOperator::Create(
|
||||||
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
|
C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
|
||||||
VK_LValue, OK_Ordinary, SourceLocation(), false);
|
SourceLocation(), false, FPOptions(C.getLangOpts()));
|
||||||
|
|
||||||
Expr *Args[2] = { &DST, &SRC };
|
Expr *Args[2] = {DST, SRC};
|
||||||
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
|
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
|
||||||
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
|
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
|
||||||
C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
|
C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
|
||||||
|
@ -3642,14 +3642,15 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
|
||||||
DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
|
DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
|
||||||
SourceLocation());
|
SourceLocation());
|
||||||
|
|
||||||
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
|
UnaryOperator *SRC = UnaryOperator::Create(
|
||||||
VK_LValue, OK_Ordinary, SourceLocation(), false);
|
C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(C.getLangOpts()));
|
||||||
|
|
||||||
CXXConstructExpr *CXXConstExpr =
|
CXXConstructExpr *CXXConstExpr =
|
||||||
cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
|
cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
|
||||||
|
|
||||||
SmallVector<Expr*, 4> ConstructorArgs;
|
SmallVector<Expr*, 4> ConstructorArgs;
|
||||||
ConstructorArgs.push_back(&SRC);
|
ConstructorArgs.push_back(SRC);
|
||||||
ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()),
|
ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()),
|
||||||
CXXConstExpr->arg_end());
|
CXXConstExpr->arg_end());
|
||||||
|
|
||||||
|
|
|
@ -3055,8 +3055,9 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
|
||||||
C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary,
|
C, &IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary,
|
||||||
S.getBeginLoc(), FPOptions(C.getLangOpts()));
|
S.getBeginLoc(), FPOptions(C.getLangOpts()));
|
||||||
// Increment for loop counter.
|
// Increment for loop counter.
|
||||||
UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
|
UnaryOperator *Inc = UnaryOperator::Create(
|
||||||
S.getBeginLoc(), true);
|
C, &IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
|
||||||
|
S.getBeginLoc(), true, FPOptions(C.getLangOpts()));
|
||||||
auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
|
auto &&BodyGen = [CapturedStmt, CS, &S, &IV](CodeGenFunction &CGF) {
|
||||||
// Iterate through all sections and emit a switch construct:
|
// Iterate through all sections and emit a switch construct:
|
||||||
// switch (IV) {
|
// switch (IV) {
|
||||||
|
@ -3126,7 +3127,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
|
||||||
// IV = LB;
|
// IV = LB;
|
||||||
CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
|
CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getBeginLoc()), IV);
|
||||||
// while (idx <= UB) { BODY; ++idx; }
|
// while (idx <= UB) { BODY; ++idx; }
|
||||||
CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, &Inc, BodyGen,
|
CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, Cond, Inc, BodyGen,
|
||||||
[](CodeGenFunction &) {});
|
[](CodeGenFunction &) {});
|
||||||
// Tell the runtime we are done.
|
// Tell the runtime we are done.
|
||||||
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
|
auto &&CodeGen = [&S](CodeGenFunction &CGF) {
|
||||||
|
|
|
@ -117,8 +117,8 @@ CodeGenFunction::~CodeGenFunction() {
|
||||||
|
|
||||||
// Map the LangOption for exception behavior into
|
// Map the LangOption for exception behavior into
|
||||||
// the corresponding enum in the IR.
|
// the corresponding enum in the IR.
|
||||||
static llvm::fp::ExceptionBehavior ToConstrainedExceptMD(
|
llvm::fp::ExceptionBehavior
|
||||||
LangOptions::FPExceptionModeKind Kind) {
|
clang::ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind) {
|
||||||
|
|
||||||
switch (Kind) {
|
switch (Kind) {
|
||||||
case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore;
|
case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore;
|
||||||
|
@ -133,15 +133,10 @@ void CodeGenFunction::SetFPModel() {
|
||||||
auto fpExceptionBehavior = ToConstrainedExceptMD(
|
auto fpExceptionBehavior = ToConstrainedExceptMD(
|
||||||
getLangOpts().getFPExceptionMode());
|
getLangOpts().getFPExceptionMode());
|
||||||
|
|
||||||
if (fpExceptionBehavior == llvm::fp::ebIgnore &&
|
Builder.setDefaultConstrainedRounding(RM);
|
||||||
RM == llvm::RoundingMode::NearestTiesToEven)
|
Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
|
||||||
// Constrained intrinsics are not used.
|
Builder.setIsFPConstrained(fpExceptionBehavior != llvm::fp::ebIgnore ||
|
||||||
;
|
RM != llvm::RoundingMode::NearestTiesToEven);
|
||||||
else {
|
|
||||||
Builder.setIsFPConstrained(true);
|
|
||||||
Builder.setDefaultConstrainedRounding(RM);
|
|
||||||
Builder.setDefaultConstrainedExcept(fpExceptionBehavior);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
|
CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
|
||||||
|
@ -919,9 +914,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
||||||
Fn->addFnAttr(llvm::Attribute::NoRecurse);
|
Fn->addFnAttr(llvm::Attribute::NoRecurse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
|
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
|
||||||
|
Builder.setIsFPConstrained(FD->usesFPIntrin());
|
||||||
if (FD->usesFPIntrin())
|
if (FD->usesFPIntrin())
|
||||||
Fn->addFnAttr(llvm::Attribute::StrictFP);
|
Fn->addFnAttr(llvm::Attribute::StrictFP);
|
||||||
|
}
|
||||||
|
|
||||||
// If a custom alignment is used, force realigning to this alignment on
|
// If a custom alignment is used, force realigning to this alignment on
|
||||||
// any main function which certainly will need it.
|
// any main function which certainly will need it.
|
||||||
|
|
|
@ -4575,6 +4575,11 @@ inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF,
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace CodeGen
|
} // end namespace CodeGen
|
||||||
|
|
||||||
|
// Map the LangOption for floating point exception behavior into
|
||||||
|
// the corresponding enum in the IR.
|
||||||
|
llvm::fp::ExceptionBehavior
|
||||||
|
ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind);
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2455,7 +2455,7 @@ static const StringRef GetInputKindName(InputKind IK) {
|
||||||
|
|
||||||
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
||||||
const TargetOptions &TargetOpts,
|
const TargetOptions &TargetOpts,
|
||||||
PreprocessorOptions &PPOpts,
|
PreprocessorOptions &PPOpts, CodeGenOptions &CGOpts,
|
||||||
DiagnosticsEngine &Diags) {
|
DiagnosticsEngine &Diags) {
|
||||||
// FIXME: Cleanup per-file based stuff.
|
// FIXME: Cleanup per-file based stuff.
|
||||||
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
|
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
|
||||||
|
@ -3187,6 +3187,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
||||||
Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
|
Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) ||
|
||||||
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
|
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
|
||||||
Args.hasArg(OPT_cl_fast_relaxed_math);
|
Args.hasArg(OPT_cl_fast_relaxed_math);
|
||||||
|
Opts.AllowFPReassoc = Opts.FastMath || CGOpts.Reassociate;
|
||||||
|
Opts.NoHonorNaNs =
|
||||||
|
Opts.FastMath || CGOpts.NoNaNsFPMath || Opts.FiniteMathOnly;
|
||||||
|
Opts.NoHonorInfs =
|
||||||
|
Opts.FastMath || CGOpts.NoInfsFPMath || Opts.FiniteMathOnly;
|
||||||
|
Opts.NoSignedZero = Opts.FastMath || CGOpts.NoSignedZeros;
|
||||||
|
Opts.AllowRecip = Opts.FastMath || CGOpts.ReciprocalMath;
|
||||||
|
// Currently there's no clang option to enable this individually
|
||||||
|
Opts.ApproxFunc = Opts.FastMath;
|
||||||
|
|
||||||
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
|
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
|
||||||
StringRef Val = A->getValue();
|
StringRef Val = A->getValue();
|
||||||
|
@ -3640,7 +3649,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
|
||||||
// Other LangOpts are only initialized when the input is not AST or LLVM IR.
|
// Other LangOpts are only initialized when the input is not AST or LLVM IR.
|
||||||
// FIXME: Should we really be calling this for an Language::Asm input?
|
// FIXME: Should we really be calling this for an Language::Asm input?
|
||||||
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
|
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
|
||||||
Res.getPreprocessorOpts(), Diags);
|
Res.getPreprocessorOpts(), Res.getCodeGenOpts(), Diags);
|
||||||
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
|
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
|
||||||
LangOpts.ObjCExceptions = 1;
|
LangOpts.ObjCExceptions = 1;
|
||||||
if (T.isOSDarwin() && DashX.isPreprocessed()) {
|
if (T.isOSDarwin() && DashX.isPreprocessed()) {
|
||||||
|
|
|
@ -2587,9 +2587,10 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
|
||||||
strType, nullptr, SC_Static);
|
strType, nullptr, SC_Static);
|
||||||
DeclRefExpr *DRE = new (Context)
|
DeclRefExpr *DRE = new (Context)
|
||||||
DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
|
DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
|
||||||
Expr *Unop = new (Context)
|
Expr *Unop = UnaryOperator::Create(
|
||||||
UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()),
|
const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary, SourceLocation(), false);
|
Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
// cast to NSConstantString *
|
// cast to NSConstantString *
|
||||||
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
|
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
|
||||||
CK_CPointerToObjCPointerCast, Unop);
|
CK_CPointerToObjCPointerCast, Unop);
|
||||||
|
@ -3283,10 +3284,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
||||||
// we need the cast below. For example:
|
// we need the cast below. For example:
|
||||||
// (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
// (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
||||||
//
|
//
|
||||||
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
|
SuperRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(SuperRep->getType()),
|
const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary,
|
Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
SourceLocation(), false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
||||||
Context->getPointerType(superType),
|
Context->getPointerType(superType),
|
||||||
CK_BitCast, SuperRep);
|
CK_BitCast, SuperRep);
|
||||||
|
@ -3301,10 +3302,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
||||||
superType, VK_LValue,
|
superType, VK_LValue,
|
||||||
ILE, false);
|
ILE, false);
|
||||||
// struct __rw_objc_super *
|
// struct __rw_objc_super *
|
||||||
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
|
SuperRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(SuperRep->getType()),
|
const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary,
|
Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
SourceLocation(), false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
}
|
}
|
||||||
MsgExprs.push_back(SuperRep);
|
MsgExprs.push_back(SuperRep);
|
||||||
break;
|
break;
|
||||||
|
@ -3378,10 +3379,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
||||||
// we need the cast below. For example:
|
// we need the cast below. For example:
|
||||||
// (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
// (struct __rw_objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
||||||
//
|
//
|
||||||
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
|
SuperRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(SuperRep->getType()),
|
const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary,
|
Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
SourceLocation(), false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
||||||
Context->getPointerType(superType),
|
Context->getPointerType(superType),
|
||||||
CK_BitCast, SuperRep);
|
CK_BitCast, SuperRep);
|
||||||
|
@ -4705,9 +4706,10 @@ Stmt *RewriteModernObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
|
||||||
if (VarDecl *Var = dyn_cast<VarDecl>(VD))
|
if (VarDecl *Var = dyn_cast<VarDecl>(VD))
|
||||||
if (!ImportedLocalExternalDecls.count(Var))
|
if (!ImportedLocalExternalDecls.count(Var))
|
||||||
return DRE;
|
return DRE;
|
||||||
Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
|
Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), DRE,
|
||||||
VK_LValue, OK_Ordinary,
|
UO_Deref, DRE->getType(), VK_LValue,
|
||||||
DRE->getLocation(), false);
|
OK_Ordinary, DRE->getLocation(), false,
|
||||||
|
FPOptions(Context->getLangOpts()));
|
||||||
// Need parens to enforce precedence.
|
// Need parens to enforce precedence.
|
||||||
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
|
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
|
||||||
Exp);
|
Exp);
|
||||||
|
@ -5293,11 +5295,12 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
VarDecl *NewVD = VarDecl::Create(
|
VarDecl *NewVD = VarDecl::Create(
|
||||||
*Context, TUDecl, SourceLocation(), SourceLocation(),
|
*Context, TUDecl, SourceLocation(), SourceLocation(),
|
||||||
&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);
|
&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);
|
||||||
UnaryOperator *DescRefExpr = new (Context) UnaryOperator(
|
UnaryOperator *DescRefExpr = UnaryOperator::Create(
|
||||||
|
const_cast<ASTContext &>(*Context),
|
||||||
new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,
|
new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,
|
||||||
VK_LValue, SourceLocation()),
|
VK_LValue, SourceLocation()),
|
||||||
UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
|
UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
|
||||||
OK_Ordinary, SourceLocation(), false);
|
OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
InitExprs.push_back(DescRefExpr);
|
InitExprs.push_back(DescRefExpr);
|
||||||
|
|
||||||
// Add initializers for any closure decl refs.
|
// Add initializers for any closure decl refs.
|
||||||
|
@ -5314,9 +5317,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
if (HasLocalVariableExternalStorage(*I)) {
|
if (HasLocalVariableExternalStorage(*I)) {
|
||||||
QualType QT = (*I)->getType();
|
QualType QT = (*I)->getType();
|
||||||
QT = Context->getPointerType(QT);
|
QT = Context->getPointerType(QT);
|
||||||
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
|
Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
|
||||||
OK_Ordinary, SourceLocation(),
|
UO_AddrOf, QT, VK_RValue, OK_Ordinary,
|
||||||
false);
|
SourceLocation(), false,
|
||||||
|
FPOptions(Context->getLangOpts()));
|
||||||
}
|
}
|
||||||
} else if (isTopLevelBlockPointerType((*I)->getType())) {
|
} else if (isTopLevelBlockPointerType((*I)->getType())) {
|
||||||
FD = SynthBlockInitFunctionDecl((*I)->getName());
|
FD = SynthBlockInitFunctionDecl((*I)->getName());
|
||||||
|
@ -5331,9 +5335,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
if (HasLocalVariableExternalStorage(*I)) {
|
if (HasLocalVariableExternalStorage(*I)) {
|
||||||
QualType QT = (*I)->getType();
|
QualType QT = (*I)->getType();
|
||||||
QT = Context->getPointerType(QT);
|
QT = Context->getPointerType(QT);
|
||||||
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
|
Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
|
||||||
OK_Ordinary, SourceLocation(),
|
UO_AddrOf, QT, VK_RValue, OK_Ordinary,
|
||||||
false);
|
SourceLocation(), false,
|
||||||
|
FPOptions(Context->getLangOpts()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5371,10 +5376,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
// captured nested byref variable has its address passed. Do not take
|
// captured nested byref variable has its address passed. Do not take
|
||||||
// its address again.
|
// its address again.
|
||||||
if (!isNestedCapturedVar)
|
if (!isNestedCapturedVar)
|
||||||
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf,
|
Exp = UnaryOperator::Create(
|
||||||
Context->getPointerType(Exp->getType()),
|
const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary, SourceLocation(),
|
Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary,
|
||||||
false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
|
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
|
||||||
InitExprs.push_back(Exp);
|
InitExprs.push_back(Exp);
|
||||||
}
|
}
|
||||||
|
@ -5398,9 +5403,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
NewRep = DRE;
|
NewRep = DRE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf,
|
NewRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(NewRep->getType()),
|
const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary, SourceLocation(), false);
|
Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
|
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
|
||||||
NewRep);
|
NewRep);
|
||||||
// Put Paren around the call.
|
// Put Paren around the call.
|
||||||
|
@ -7539,10 +7545,10 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
|
||||||
CK_BitCast,
|
CK_BitCast,
|
||||||
PE);
|
PE);
|
||||||
|
|
||||||
|
Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context),
|
||||||
Expr *Exp = new (Context) UnaryOperator(castExpr, UO_Deref, IvarT,
|
castExpr, UO_Deref, IvarT, VK_LValue,
|
||||||
VK_LValue, OK_Ordinary,
|
OK_Ordinary, SourceLocation(), false,
|
||||||
SourceLocation(), false);
|
FPOptions(Context->getLangOpts()));
|
||||||
PE = new (Context) ParenExpr(OldRange.getBegin(),
|
PE = new (Context) ParenExpr(OldRange.getBegin(),
|
||||||
OldRange.getEnd(),
|
OldRange.getEnd(),
|
||||||
Exp);
|
Exp);
|
||||||
|
|
|
@ -2514,9 +2514,10 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
|
||||||
strType, nullptr, SC_Static);
|
strType, nullptr, SC_Static);
|
||||||
DeclRefExpr *DRE = new (Context)
|
DeclRefExpr *DRE = new (Context)
|
||||||
DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
|
DeclRefExpr(*Context, NewVD, false, strType, VK_LValue, SourceLocation());
|
||||||
Expr *Unop = new (Context)
|
Expr *Unop = UnaryOperator::Create(
|
||||||
UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()),
|
const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary, SourceLocation(), false);
|
Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
// cast to NSConstantString *
|
// cast to NSConstantString *
|
||||||
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
|
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
|
||||||
CK_CPointerToObjCPointerCast, Unop);
|
CK_CPointerToObjCPointerCast, Unop);
|
||||||
|
@ -2714,10 +2715,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
||||||
// we need the cast below. For example:
|
// we need the cast below. For example:
|
||||||
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
||||||
//
|
//
|
||||||
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
|
SuperRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(SuperRep->getType()),
|
const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary,
|
Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
SourceLocation(), false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
||||||
Context->getPointerType(superType),
|
Context->getPointerType(superType),
|
||||||
CK_BitCast, SuperRep);
|
CK_BitCast, SuperRep);
|
||||||
|
@ -2732,10 +2733,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
||||||
superType, VK_LValue,
|
superType, VK_LValue,
|
||||||
ILE, false);
|
ILE, false);
|
||||||
// struct objc_super *
|
// struct objc_super *
|
||||||
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
|
SuperRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(SuperRep->getType()),
|
const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary,
|
Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
SourceLocation(), false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
}
|
}
|
||||||
MsgExprs.push_back(SuperRep);
|
MsgExprs.push_back(SuperRep);
|
||||||
break;
|
break;
|
||||||
|
@ -2809,10 +2810,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
|
||||||
// we need the cast below. For example:
|
// we need the cast below. For example:
|
||||||
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
|
||||||
//
|
//
|
||||||
SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf,
|
SuperRep = UnaryOperator::Create(
|
||||||
Context->getPointerType(SuperRep->getType()),
|
const_cast<ASTContext &>(*Context), SuperRep, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary,
|
Context->getPointerType(SuperRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
SourceLocation(), false);
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
||||||
Context->getPointerType(superType),
|
Context->getPointerType(superType),
|
||||||
CK_BitCast, SuperRep);
|
CK_BitCast, SuperRep);
|
||||||
|
@ -3048,9 +3049,10 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
|
||||||
nullptr, SC_Extern);
|
nullptr, SC_Extern);
|
||||||
DeclRefExpr *DRE = new (Context) DeclRefExpr(
|
DeclRefExpr *DRE = new (Context) DeclRefExpr(
|
||||||
*Context, VD, false, getProtocolType(), VK_LValue, SourceLocation());
|
*Context, VD, false, getProtocolType(), VK_LValue, SourceLocation());
|
||||||
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
|
Expr *DerefExpr = UnaryOperator::Create(
|
||||||
Context->getPointerType(DRE->getType()),
|
const_cast<ASTContext &>(*Context), DRE, UO_AddrOf,
|
||||||
VK_RValue, OK_Ordinary, SourceLocation(), false);
|
Context->getPointerType(DRE->getType()), VK_RValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
|
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
|
||||||
CK_BitCast,
|
CK_BitCast,
|
||||||
DerefExpr);
|
DerefExpr);
|
||||||
|
@ -3875,9 +3877,10 @@ Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) {
|
||||||
if (VarDecl *Var = dyn_cast<VarDecl>(VD))
|
if (VarDecl *Var = dyn_cast<VarDecl>(VD))
|
||||||
if (!ImportedLocalExternalDecls.count(Var))
|
if (!ImportedLocalExternalDecls.count(Var))
|
||||||
return DRE;
|
return DRE;
|
||||||
Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(),
|
Expr *Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), DRE,
|
||||||
VK_LValue, OK_Ordinary,
|
UO_Deref, DRE->getType(), VK_LValue,
|
||||||
DRE->getLocation(), false);
|
OK_Ordinary, DRE->getLocation(), false,
|
||||||
|
FPOptions(Context->getLangOpts()));
|
||||||
// Need parens to enforce precedence.
|
// Need parens to enforce precedence.
|
||||||
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
|
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
|
||||||
Exp);
|
Exp);
|
||||||
|
@ -4432,11 +4435,12 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
VarDecl *NewVD = VarDecl::Create(
|
VarDecl *NewVD = VarDecl::Create(
|
||||||
*Context, TUDecl, SourceLocation(), SourceLocation(),
|
*Context, TUDecl, SourceLocation(), SourceLocation(),
|
||||||
&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);
|
&Context->Idents.get(DescData), Context->VoidPtrTy, nullptr, SC_Static);
|
||||||
UnaryOperator *DescRefExpr = new (Context) UnaryOperator(
|
UnaryOperator *DescRefExpr = UnaryOperator::Create(
|
||||||
|
const_cast<ASTContext &>(*Context),
|
||||||
new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,
|
new (Context) DeclRefExpr(*Context, NewVD, false, Context->VoidPtrTy,
|
||||||
VK_LValue, SourceLocation()),
|
VK_LValue, SourceLocation()),
|
||||||
UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
|
UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), VK_RValue,
|
||||||
OK_Ordinary, SourceLocation(), false);
|
OK_Ordinary, SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
InitExprs.push_back(DescRefExpr);
|
InitExprs.push_back(DescRefExpr);
|
||||||
|
|
||||||
// Add initializers for any closure decl refs.
|
// Add initializers for any closure decl refs.
|
||||||
|
@ -4453,9 +4457,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
if (HasLocalVariableExternalStorage(*I)) {
|
if (HasLocalVariableExternalStorage(*I)) {
|
||||||
QualType QT = (*I)->getType();
|
QualType QT = (*I)->getType();
|
||||||
QT = Context->getPointerType(QT);
|
QT = Context->getPointerType(QT);
|
||||||
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
|
Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
|
||||||
OK_Ordinary, SourceLocation(),
|
UO_AddrOf, QT, VK_RValue, OK_Ordinary,
|
||||||
false);
|
SourceLocation(), false,
|
||||||
|
FPOptions(Context->getLangOpts()));
|
||||||
}
|
}
|
||||||
} else if (isTopLevelBlockPointerType((*I)->getType())) {
|
} else if (isTopLevelBlockPointerType((*I)->getType())) {
|
||||||
FD = SynthBlockInitFunctionDecl((*I)->getName());
|
FD = SynthBlockInitFunctionDecl((*I)->getName());
|
||||||
|
@ -4470,9 +4475,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
if (HasLocalVariableExternalStorage(*I)) {
|
if (HasLocalVariableExternalStorage(*I)) {
|
||||||
QualType QT = (*I)->getType();
|
QualType QT = (*I)->getType();
|
||||||
QT = Context->getPointerType(QT);
|
QT = Context->getPointerType(QT);
|
||||||
Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, VK_RValue,
|
Exp = UnaryOperator::Create(const_cast<ASTContext &>(*Context), Exp,
|
||||||
OK_Ordinary, SourceLocation(),
|
UO_AddrOf, QT, VK_RValue, OK_Ordinary,
|
||||||
false);
|
SourceLocation(), false,
|
||||||
|
FPOptions(Context->getLangOpts()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InitExprs.push_back(Exp);
|
InitExprs.push_back(Exp);
|
||||||
|
@ -4509,9 +4515,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
// captured nested byref variable has its address passed. Do not take
|
// captured nested byref variable has its address passed. Do not take
|
||||||
// its address again.
|
// its address again.
|
||||||
if (!isNestedCapturedVar)
|
if (!isNestedCapturedVar)
|
||||||
Exp = new (Context) UnaryOperator(
|
Exp = UnaryOperator::Create(
|
||||||
Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), VK_RValue,
|
const_cast<ASTContext &>(*Context), Exp, UO_AddrOf,
|
||||||
OK_Ordinary, SourceLocation(), false);
|
Context->getPointerType(Exp->getType()), VK_RValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
|
Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_BitCast, Exp);
|
||||||
InitExprs.push_back(Exp);
|
InitExprs.push_back(Exp);
|
||||||
}
|
}
|
||||||
|
@ -4527,9 +4534,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
|
||||||
}
|
}
|
||||||
NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,
|
NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,
|
||||||
SourceLocation());
|
SourceLocation());
|
||||||
NewRep = new (Context) UnaryOperator(
|
NewRep = UnaryOperator::Create(
|
||||||
NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue,
|
const_cast<ASTContext &>(*Context), NewRep, UO_AddrOf,
|
||||||
OK_Ordinary, SourceLocation(), false);
|
Context->getPointerType(NewRep->getType()), VK_RValue, OK_Ordinary,
|
||||||
|
SourceLocation(), false, FPOptions(Context->getLangOpts()));
|
||||||
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
|
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_BitCast,
|
||||||
NewRep);
|
NewRep);
|
||||||
BlockDeclRefs.clear();
|
BlockDeclRefs.clear();
|
||||||
|
|
|
@ -3365,6 +3365,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
||||||
// are complete and we can parse the delayed portions of method
|
// are complete and we can parse the delayed portions of method
|
||||||
// declarations and the lexed inline method definitions, along with any
|
// declarations and the lexed inline method definitions, along with any
|
||||||
// delayed attributes.
|
// delayed attributes.
|
||||||
|
|
||||||
|
// Save the state of Sema.FPFeatures, and change the setting
|
||||||
|
// 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());
|
||||||
|
|
||||||
SourceLocation SavedPrevTokLocation = PrevTokLocation;
|
SourceLocation SavedPrevTokLocation = PrevTokLocation;
|
||||||
ParseLexedPragmas(getCurrentClass());
|
ParseLexedPragmas(getCurrentClass());
|
||||||
ParseLexedAttributes(getCurrentClass());
|
ParseLexedAttributes(getCurrentClass());
|
||||||
|
|
|
@ -184,6 +184,13 @@ private:
|
||||||
Sema &Actions;
|
Sema &Actions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PragmaFloatControlHandler : public PragmaHandler {
|
||||||
|
PragmaFloatControlHandler(Sema &Actions)
|
||||||
|
: PragmaHandler("float_control") {}
|
||||||
|
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||||
|
Token &FirstToken) override;
|
||||||
|
};
|
||||||
|
|
||||||
struct PragmaMSPointersToMembers : public PragmaHandler {
|
struct PragmaMSPointersToMembers : public PragmaHandler {
|
||||||
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
|
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
|
||||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||||
|
@ -334,6 +341,8 @@ void Parser::initializePragmaHandlers() {
|
||||||
PP.AddPragmaHandler(MSCommentHandler.get());
|
PP.AddPragmaHandler(MSCommentHandler.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FloatControlHandler = std::make_unique<PragmaFloatControlHandler>(Actions);
|
||||||
|
PP.AddPragmaHandler(FloatControlHandler.get());
|
||||||
if (getLangOpts().MicrosoftExt) {
|
if (getLangOpts().MicrosoftExt) {
|
||||||
MSDetectMismatchHandler =
|
MSDetectMismatchHandler =
|
||||||
std::make_unique<PragmaDetectMismatchHandler>(Actions);
|
std::make_unique<PragmaDetectMismatchHandler>(Actions);
|
||||||
|
@ -438,6 +447,8 @@ void Parser::resetPragmaHandlers() {
|
||||||
PP.RemovePragmaHandler("clang", PCSectionHandler.get());
|
PP.RemovePragmaHandler("clang", PCSectionHandler.get());
|
||||||
PCSectionHandler.reset();
|
PCSectionHandler.reset();
|
||||||
|
|
||||||
|
PP.RemovePragmaHandler(FloatControlHandler.get());
|
||||||
|
FloatControlHandler.reset();
|
||||||
if (getLangOpts().MicrosoftExt) {
|
if (getLangOpts().MicrosoftExt) {
|
||||||
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
|
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
|
||||||
MSDetectMismatchHandler.reset();
|
MSDetectMismatchHandler.reset();
|
||||||
|
@ -646,6 +657,22 @@ void Parser::HandlePragmaFPContract() {
|
||||||
ConsumeAnnotationToken();
|
ConsumeAnnotationToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::HandlePragmaFloatControl() {
|
||||||
|
assert(Tok.is(tok::annot_pragma_float_control));
|
||||||
|
|
||||||
|
// The value that is held on the PragmaFloatControlStack encodes
|
||||||
|
// the PragmaFloatControl kind and the MSStackAction kind
|
||||||
|
// into a single 32-bit word. The MsStackAction is the high 16 bits
|
||||||
|
// and the FloatControl is the lower 16 bits. Use shift and bit-and
|
||||||
|
// to decode the parts.
|
||||||
|
uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
|
||||||
|
Sema::PragmaMsStackAction Action =
|
||||||
|
static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
|
||||||
|
PragmaFloatControlKind Kind = PragmaFloatControlKind(Value & 0xFFFF);
|
||||||
|
SourceLocation PragmaLoc = ConsumeAnnotationToken();
|
||||||
|
Actions.ActOnPragmaFloatControl(PragmaLoc, Action, Kind);
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::HandlePragmaFEnvAccess() {
|
void Parser::HandlePragmaFEnvAccess() {
|
||||||
assert(Tok.is(tok::annot_pragma_fenv_access));
|
assert(Tok.is(tok::annot_pragma_fenv_access));
|
||||||
tok::OnOffSwitch OOS =
|
tok::OnOffSwitch OOS =
|
||||||
|
@ -665,8 +692,8 @@ void Parser::HandlePragmaFEnvAccess() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions.ActOnPragmaFEnvAccess(FPC);
|
SourceLocation PragmaLoc = ConsumeAnnotationToken();
|
||||||
ConsumeAnnotationToken();
|
Actions.ActOnPragmaFEnvAccess(PragmaLoc, FPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2489,6 +2516,129 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP,
|
||||||
PP.EnterToken(AnnotTok, /*IsReinject*/ false);
|
PP.EnterToken(AnnotTok, /*IsReinject*/ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle the \#pragma float_control extension.
|
||||||
|
///
|
||||||
|
/// The syntax is:
|
||||||
|
/// \code
|
||||||
|
/// #pragma float_control(keyword[, setting] [,push])
|
||||||
|
/// \endcode
|
||||||
|
/// Where 'keyword' and 'setting' are identifiers.
|
||||||
|
// 'keyword' can be: precise, except, push, pop
|
||||||
|
// 'setting' can be: on, off
|
||||||
|
/// The optional arguments 'setting' and 'push' are supported only
|
||||||
|
/// when the keyword is 'precise' or 'except'.
|
||||||
|
void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP,
|
||||||
|
PragmaIntroducer Introducer,
|
||||||
|
Token &Tok) {
|
||||||
|
Sema::PragmaMsStackAction Action = Sema::PSK_Set;
|
||||||
|
SourceLocation FloatControlLoc = Tok.getLocation();
|
||||||
|
PP.Lex(Tok);
|
||||||
|
if (Tok.isNot(tok::l_paren)) {
|
||||||
|
PP.Diag(FloatControlLoc, diag::err_expected) << tok::l_paren;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the identifier.
|
||||||
|
PP.Lex(Tok);
|
||||||
|
if (Tok.isNot(tok::identifier)) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that this is one of the float control options.
|
||||||
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||||
|
PragmaFloatControlKind Kind =
|
||||||
|
llvm::StringSwitch<PragmaFloatControlKind>(II->getName())
|
||||||
|
.Case("precise", PFC_Precise)
|
||||||
|
.Case("except", PFC_Except)
|
||||||
|
.Case("push", PFC_Push)
|
||||||
|
.Case("pop", PFC_Pop)
|
||||||
|
.Default(PFC_Unknown);
|
||||||
|
PP.Lex(Tok); // the identifier
|
||||||
|
if (Kind == PFC_Unknown) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
} else if (Kind == PFC_Push || Kind == PFC_Pop) {
|
||||||
|
if (Tok.isNot(tok::r_paren)) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PP.Lex(Tok); // Eat the r_paren
|
||||||
|
Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push;
|
||||||
|
} else {
|
||||||
|
if (Tok.is(tok::r_paren))
|
||||||
|
// Selecting Precise or Except
|
||||||
|
PP.Lex(Tok); // the r_paren
|
||||||
|
else if (Tok.isNot(tok::comma)) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
PP.Lex(Tok); // ,
|
||||||
|
if (!Tok.isAnyIdentifier()) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StringRef PushOnOff = Tok.getIdentifierInfo()->getName();
|
||||||
|
if (PushOnOff == "on")
|
||||||
|
// Kind is set correctly
|
||||||
|
;
|
||||||
|
else if (PushOnOff == "off") {
|
||||||
|
if (Kind == PFC_Precise)
|
||||||
|
Kind = PFC_NoPrecise;
|
||||||
|
if (Kind == PFC_Except)
|
||||||
|
Kind = PFC_NoExcept;
|
||||||
|
} else if (PushOnOff == "push") {
|
||||||
|
Action = Sema::PSK_Push_Set;
|
||||||
|
} else {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PP.Lex(Tok); // the identifier
|
||||||
|
if (Tok.is(tok::comma)) {
|
||||||
|
PP.Lex(Tok); // ,
|
||||||
|
if (!Tok.isAnyIdentifier()) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StringRef ExpectedPush = Tok.getIdentifierInfo()->getName();
|
||||||
|
if (ExpectedPush == "push") {
|
||||||
|
Action = Sema::PSK_Push_Set;
|
||||||
|
} else {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PP.Lex(Tok); // the push identifier
|
||||||
|
}
|
||||||
|
if (Tok.isNot(tok::r_paren)) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PP.Lex(Tok); // the r_paren
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SourceLocation EndLoc = Tok.getLocation();
|
||||||
|
if (Tok.isNot(tok::eod)) {
|
||||||
|
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||||
|
<< "float_control";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: there is no accomodation for PP callback for this pragma.
|
||||||
|
|
||||||
|
// Enter the annotation.
|
||||||
|
auto TokenArray = std::make_unique<Token[]>(1);
|
||||||
|
TokenArray[0].startToken();
|
||||||
|
TokenArray[0].setKind(tok::annot_pragma_float_control);
|
||||||
|
TokenArray[0].setLocation(FloatControlLoc);
|
||||||
|
TokenArray[0].setAnnotationEndLoc(EndLoc);
|
||||||
|
// Create an encoding of Action and Value by shifting the Action into
|
||||||
|
// the high 16 bits then union with the Kind.
|
||||||
|
TokenArray[0].setAnnotationValue(reinterpret_cast<void *>(
|
||||||
|
static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF))));
|
||||||
|
PP.EnterTokenStream(std::move(TokenArray), 1,
|
||||||
|
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle the Microsoft \#pragma detect_mismatch extension.
|
/// Handle the Microsoft \#pragma detect_mismatch extension.
|
||||||
///
|
///
|
||||||
/// The syntax is:
|
/// The syntax is:
|
||||||
|
@ -2749,7 +2899,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
||||||
|
|
||||||
auto *AnnotValue = new (PP.getPreprocessorAllocator())
|
auto *AnnotValue = new (PP.getPreprocessorAllocator())
|
||||||
TokFPAnnotValue{*FlagKind, *FlagValue};
|
TokFPAnnotValue{*FlagKind, *FlagValue};
|
||||||
// Generate the loop hint token.
|
// Generate the fp annotation token.
|
||||||
Token FPTok;
|
Token FPTok;
|
||||||
FPTok.startToken();
|
FPTok.startToken();
|
||||||
FPTok.setKind(tok::annot_pragma_fp);
|
FPTok.setKind(tok::annot_pragma_fp);
|
||||||
|
|
|
@ -354,13 +354,13 @@ Retry:
|
||||||
|
|
||||||
case tok::annot_pragma_fp_contract:
|
case tok::annot_pragma_fp_contract:
|
||||||
ProhibitAttributes(Attrs);
|
ProhibitAttributes(Attrs);
|
||||||
Diag(Tok, diag::err_pragma_fp_contract_scope);
|
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract";
|
||||||
ConsumeAnnotationToken();
|
ConsumeAnnotationToken();
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
case tok::annot_pragma_fp:
|
case tok::annot_pragma_fp:
|
||||||
ProhibitAttributes(Attrs);
|
ProhibitAttributes(Attrs);
|
||||||
Diag(Tok, diag::err_pragma_fp_scope);
|
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp";
|
||||||
ConsumeAnnotationToken();
|
ConsumeAnnotationToken();
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
|
@ -369,6 +369,12 @@ Retry:
|
||||||
HandlePragmaFEnvAccess();
|
HandlePragmaFEnvAccess();
|
||||||
return StmtEmpty();
|
return StmtEmpty();
|
||||||
|
|
||||||
|
case tok::annot_pragma_float_control:
|
||||||
|
ProhibitAttributes(Attrs);
|
||||||
|
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
|
||||||
|
ConsumeAnnotationToken();
|
||||||
|
return StmtError();
|
||||||
|
|
||||||
case tok::annot_pragma_opencl_extension:
|
case tok::annot_pragma_opencl_extension:
|
||||||
ProhibitAttributes(Attrs);
|
ProhibitAttributes(Attrs);
|
||||||
HandlePragmaOpenCLExtension();
|
HandlePragmaOpenCLExtension();
|
||||||
|
@ -937,6 +943,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
|
||||||
case tok::annot_pragma_fenv_access:
|
case tok::annot_pragma_fenv_access:
|
||||||
HandlePragmaFEnvAccess();
|
HandlePragmaFEnvAccess();
|
||||||
break;
|
break;
|
||||||
|
case tok::annot_pragma_float_control:
|
||||||
|
HandlePragmaFloatControl();
|
||||||
|
break;
|
||||||
case tok::annot_pragma_ms_pointers_to_members:
|
case tok::annot_pragma_ms_pointers_to_members:
|
||||||
HandlePragmaMSPointersToMembers();
|
HandlePragmaMSPointersToMembers();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -752,6 +752,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
|
||||||
case tok::annot_pragma_fenv_access:
|
case tok::annot_pragma_fenv_access:
|
||||||
HandlePragmaFEnvAccess();
|
HandlePragmaFEnvAccess();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
case tok::annot_pragma_float_control:
|
||||||
|
HandlePragmaFloatControl();
|
||||||
|
return nullptr;
|
||||||
case tok::annot_pragma_fp:
|
case tok::annot_pragma_fp:
|
||||||
HandlePragmaFP();
|
HandlePragmaFP();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -159,7 +159,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
||||||
LangOpts.getMSPointerToMemberRepresentationMethod()),
|
LangOpts.getMSPointerToMemberRepresentationMethod()),
|
||||||
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
|
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
|
||||||
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
|
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
|
||||||
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
|
CodeSegStack(nullptr), FpPragmaStack(CurFPFeatures.getAsOpaqueInt()),
|
||||||
|
CurInitSeg(nullptr), VisContext(nullptr),
|
||||||
PragmaAttributeCurrentTargetDecl(nullptr),
|
PragmaAttributeCurrentTargetDecl(nullptr),
|
||||||
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
|
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
|
||||||
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
|
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
|
||||||
|
|
|
@ -407,6 +407,65 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
|
||||||
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
|
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
|
||||||
|
PragmaMsStackAction Action,
|
||||||
|
PragmaFloatControlKind Value) {
|
||||||
|
auto NewValue = FpPragmaStack.CurrentValue;
|
||||||
|
FPOptions NewFPFeatures(NewValue);
|
||||||
|
if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) &&
|
||||||
|
!CurContext->isTranslationUnit()) {
|
||||||
|
// Push and pop can only occur at file scope.
|
||||||
|
Diag(Loc, diag::err_pragma_fc_pp_scope);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (Value) {
|
||||||
|
default:
|
||||||
|
llvm_unreachable("invalid pragma float_control kind");
|
||||||
|
case PFC_Precise:
|
||||||
|
CurFPFeatures.setFPPreciseEnabled(true);
|
||||||
|
NewValue = CurFPFeatures.getAsOpaqueInt();
|
||||||
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
|
||||||
|
break;
|
||||||
|
case PFC_NoPrecise:
|
||||||
|
if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict)
|
||||||
|
Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept);
|
||||||
|
else if (CurFPFeatures.allowFEnvAccess())
|
||||||
|
Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv);
|
||||||
|
else
|
||||||
|
CurFPFeatures.setFPPreciseEnabled(false);
|
||||||
|
NewValue = CurFPFeatures.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();
|
||||||
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
|
||||||
|
break;
|
||||||
|
case PFC_NoExcept:
|
||||||
|
CurFPFeatures.setExceptionMode(LangOptions::FPE_Ignore);
|
||||||
|
NewValue = CurFPFeatures.getAsOpaqueInt();
|
||||||
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
|
||||||
|
break;
|
||||||
|
case PFC_Push:
|
||||||
|
Action = Sema::PSK_Push_Set;
|
||||||
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt());
|
||||||
|
break;
|
||||||
|
case PFC_Pop:
|
||||||
|
if (FpPragmaStack.Stack.empty()) {
|
||||||
|
Diag(Loc, diag::warn_pragma_pop_failed) << "float_control"
|
||||||
|
<< "stack empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt());
|
||||||
|
NewValue = FpPragmaStack.CurrentValue;
|
||||||
|
CurFPFeatures.getFromOpaqueInt(NewValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::ActOnPragmaMSPointersToMembers(
|
void Sema::ActOnPragmaMSPointersToMembers(
|
||||||
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
|
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
|
||||||
SourceLocation PragmaLoc) {
|
SourceLocation PragmaLoc) {
|
||||||
|
@ -948,9 +1007,16 @@ void Sema::setExceptionMode(LangOptions::FPExceptionModeKind FPE) {
|
||||||
CurFPFeatures.setExceptionMode(FPE);
|
CurFPFeatures.setExceptionMode(FPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
|
void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc,
|
||||||
|
LangOptions::FEnvAccessModeKind FPC) {
|
||||||
switch (FPC) {
|
switch (FPC) {
|
||||||
case LangOptions::FEA_On:
|
case LangOptions::FEA_On:
|
||||||
|
// Verify Microsoft restriction:
|
||||||
|
// You can't enable fenv_access unless precise semantics are enabled.
|
||||||
|
// Precise semantics can be enabled either by the float_control
|
||||||
|
// pragma, or by using the /fp:precise or /fp:strict compiler options
|
||||||
|
if (!isPreciseFPEnabled())
|
||||||
|
Diag(Loc, diag::err_pragma_fenv_requires_precise);
|
||||||
CurFPFeatures.setAllowFEnvAccess();
|
CurFPFeatures.setAllowFEnvAccess();
|
||||||
break;
|
break;
|
||||||
case LangOptions::FEA_Off:
|
case LangOptions::FEA_Off:
|
||||||
|
@ -959,7 +1025,6 @@ void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
|
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
|
||||||
SourceLocation Loc) {
|
SourceLocation Loc) {
|
||||||
// Visibility calculations will consider the namespace's visibility.
|
// Visibility calculations will consider the namespace's visibility.
|
||||||
|
|
|
@ -13455,13 +13455,13 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
|
||||||
// directly construct UnaryOperators here because semantic analysis
|
// directly construct UnaryOperators here because semantic analysis
|
||||||
// does not permit us to take the address of an xvalue.
|
// does not permit us to take the address of an xvalue.
|
||||||
Expr *From = FromB.build(S, Loc);
|
Expr *From = FromB.build(S, Loc);
|
||||||
From = new (S.Context) UnaryOperator(From, UO_AddrOf,
|
From = UnaryOperator::Create(
|
||||||
S.Context.getPointerType(From->getType()),
|
S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()),
|
||||||
VK_RValue, OK_Ordinary, Loc, false);
|
VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatures);
|
||||||
Expr *To = ToB.build(S, Loc);
|
Expr *To = ToB.build(S, Loc);
|
||||||
To = new (S.Context) UnaryOperator(To, UO_AddrOf,
|
To = UnaryOperator::Create(S.Context, To, UO_AddrOf,
|
||||||
S.Context.getPointerType(To->getType()),
|
S.Context.getPointerType(To->getType()), VK_RValue,
|
||||||
VK_RValue, OK_Ordinary, Loc, false);
|
OK_Ordinary, Loc, false, S.CurFPFeatures);
|
||||||
|
|
||||||
const Type *E = T->getBaseElementTypeUnsafe();
|
const Type *E = T->getBaseElementTypeUnsafe();
|
||||||
bool NeedsCollectableMemCpy =
|
bool NeedsCollectableMemCpy =
|
||||||
|
@ -13703,9 +13703,9 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
|
||||||
// Create the pre-increment of the iteration variable. We can determine
|
// Create the pre-increment of the iteration variable. We can determine
|
||||||
// whether the increment will overflow based on the value of the array
|
// whether the increment will overflow based on the value of the array
|
||||||
// bound.
|
// bound.
|
||||||
Expr *Increment = new (S.Context)
|
Expr *Increment = UnaryOperator::Create(
|
||||||
UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType,
|
S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue,
|
||||||
VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue());
|
OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatures);
|
||||||
|
|
||||||
// Construct the loop that copies all elements of this array.
|
// Construct the loop that copies all elements of this array.
|
||||||
return S.ActOnForStmt(
|
return S.ActOnForStmt(
|
||||||
|
|
|
@ -13662,14 +13662,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||||
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
|
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if (ResultTy->isRealFloatingType() &&
|
|
||||||
(getLangOpts().getFPRoundingMode() != RoundingMode::NearestTiesToEven ||
|
|
||||||
getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
|
|
||||||
// Mark the current function as usng floating point constrained intrinsics
|
|
||||||
if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
|
|
||||||
F->setUsesFPIntrin(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some of the binary operations require promoting operands of half vector to
|
// Some of the binary operations require promoting operands of half vector to
|
||||||
// float vectors and truncating the result back to half vector. For now, we do
|
// float vectors and truncating the result back to half vector. For now, we do
|
||||||
// this only when HalfArgsAndReturn is set (that is, when the target is arm or
|
// this only when HalfArgsAndReturn is set (that is, when the target is arm or
|
||||||
|
@ -14319,8 +14311,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
|
||||||
if (Opc != UO_AddrOf && Opc != UO_Deref)
|
if (Opc != UO_AddrOf && Opc != UO_Deref)
|
||||||
CheckArrayAccess(Input.get());
|
CheckArrayAccess(Input.get());
|
||||||
|
|
||||||
auto *UO = new (Context)
|
auto *UO = UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK,
|
||||||
UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow);
|
OK, OpLoc, CanOverflow, CurFPFeatures);
|
||||||
|
|
||||||
if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
|
if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
|
||||||
!isa<ArrayType>(UO->getType().getDesugaredType(Context)))
|
!isa<ArrayType>(UO->getType().getDesugaredType(Context)))
|
||||||
|
|
|
@ -4427,9 +4427,9 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
|
||||||
} else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
|
} else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
|
||||||
assert(uo->getOpcode() == UO_Extension);
|
assert(uo->getOpcode() == UO_Extension);
|
||||||
Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
|
Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
|
||||||
return new (Context)
|
return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(),
|
||||||
UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(),
|
sub->getValueKind(), sub->getObjectKind(),
|
||||||
sub->getObjectKind(), uo->getOperatorLoc(), false);
|
uo->getOperatorLoc(), false, CurFPFeatures);
|
||||||
} else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
|
} else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
|
||||||
assert(!gse->isResultDependent());
|
assert(!gse->isResultDependent());
|
||||||
|
|
||||||
|
|
|
@ -13001,8 +13001,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
|
||||||
|
|
||||||
if (Input->isTypeDependent()) {
|
if (Input->isTypeDependent()) {
|
||||||
if (Fns.empty())
|
if (Fns.empty())
|
||||||
return new (Context) UnaryOperator(Input, Opc, Context.DependentTy,
|
return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy,
|
||||||
VK_RValue, OK_Ordinary, OpLoc, false);
|
VK_RValue, OK_Ordinary, OpLoc, false,
|
||||||
|
CurFPFeatures);
|
||||||
|
|
||||||
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
|
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
|
||||||
UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
|
UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
|
||||||
|
@ -14802,9 +14803,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
|
||||||
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
|
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
|
||||||
(void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
|
(void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
|
||||||
|
|
||||||
return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType,
|
return UnaryOperator::Create(
|
||||||
VK_RValue, OK_Ordinary,
|
Context, SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary,
|
||||||
UnOp->getOperatorLoc(), false);
|
UnOp->getOperatorLoc(), false, CurFPFeatures);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
|
Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
|
||||||
|
@ -14812,10 +14813,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
|
||||||
if (SubExpr == UnOp->getSubExpr())
|
if (SubExpr == UnOp->getSubExpr())
|
||||||
return UnOp;
|
return UnOp;
|
||||||
|
|
||||||
return new (Context) UnaryOperator(SubExpr, UO_AddrOf,
|
return UnaryOperator::Create(
|
||||||
Context.getPointerType(SubExpr->getType()),
|
Context, SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()),
|
||||||
VK_RValue, OK_Ordinary,
|
VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(), false, CurFPFeatures);
|
||||||
UnOp->getOperatorLoc(), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
|
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
|
||||||
|
|
|
@ -127,12 +127,10 @@ namespace {
|
||||||
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
|
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
|
||||||
assert(uop->getOpcode() == UO_Extension);
|
assert(uop->getOpcode() == UO_Extension);
|
||||||
e = rebuild(uop->getSubExpr());
|
e = rebuild(uop->getSubExpr());
|
||||||
return new (S.Context) UnaryOperator(e, uop->getOpcode(),
|
return UnaryOperator::Create(
|
||||||
uop->getType(),
|
S.Context, e, uop->getOpcode(), uop->getType(), uop->getValueKind(),
|
||||||
uop->getValueKind(),
|
uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(),
|
||||||
uop->getObjectKind(),
|
S.CurFPFeatures);
|
||||||
uop->getOperatorLoc(),
|
|
||||||
uop->canOverflow());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
|
if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
|
||||||
|
@ -526,12 +524,14 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
|
||||||
(result.get()->isTypeDependent() || CanCaptureValue(result.get())))
|
(result.get()->isTypeDependent() || CanCaptureValue(result.get())))
|
||||||
setResultToLastSemantic();
|
setResultToLastSemantic();
|
||||||
|
|
||||||
UnaryOperator *syntactic = new (S.Context) UnaryOperator(
|
UnaryOperator *syntactic =
|
||||||
syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc,
|
UnaryOperator::Create(S.Context, syntacticOp, opcode, resultType,
|
||||||
!resultType->isDependentType()
|
VK_LValue, OK_Ordinary, opcLoc,
|
||||||
? S.Context.getTypeSize(resultType) >=
|
!resultType->isDependentType()
|
||||||
S.Context.getTypeSize(S.Context.IntTy)
|
? S.Context.getTypeSize(resultType) >=
|
||||||
: false);
|
S.Context.getTypeSize(S.Context.IntTy)
|
||||||
|
: false,
|
||||||
|
S.CurFPFeatures);
|
||||||
return complete(syntactic);
|
return complete(syntactic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,8 +1551,9 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
|
||||||
UnaryOperatorKind opcode, Expr *op) {
|
UnaryOperatorKind opcode, Expr *op) {
|
||||||
// Do nothing if the operand is dependent.
|
// Do nothing if the operand is dependent.
|
||||||
if (op->isTypeDependent())
|
if (op->isTypeDependent())
|
||||||
return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
|
return UnaryOperator::Create(Context, op, opcode, Context.DependentTy,
|
||||||
VK_RValue, OK_Ordinary, opcLoc, false);
|
VK_RValue, OK_Ordinary, opcLoc, false,
|
||||||
|
CurFPFeatures);
|
||||||
|
|
||||||
assert(UnaryOperator::isIncrementDecrementOp(opcode));
|
assert(UnaryOperator::isIncrementDecrementOp(opcode));
|
||||||
Expr *opaqueRef = op->IgnoreParens();
|
Expr *opaqueRef = op->IgnoreParens();
|
||||||
|
@ -1636,9 +1637,10 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
|
||||||
Expr *syntax = E->getSyntacticForm();
|
Expr *syntax = E->getSyntacticForm();
|
||||||
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
|
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
|
||||||
Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
|
Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
|
||||||
return new (Context) UnaryOperator(
|
return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(),
|
||||||
op, uop->getOpcode(), uop->getType(), uop->getValueKind(),
|
uop->getValueKind(), uop->getObjectKind(),
|
||||||
uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow());
|
uop->getOperatorLoc(), uop->canOverflow(),
|
||||||
|
CurFPFeatures);
|
||||||
} else if (CompoundAssignOperator *cop
|
} else if (CompoundAssignOperator *cop
|
||||||
= dyn_cast<CompoundAssignOperator>(syntax)) {
|
= dyn_cast<CompoundAssignOperator>(syntax)) {
|
||||||
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
|
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
|
||||||
|
|
|
@ -394,6 +394,11 @@ 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) {
|
||||||
|
|
|
@ -3779,6 +3779,29 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case FLOAT_CONTROL_PRAGMA_OPTIONS: {
|
||||||
|
if (Record.size() < 3) {
|
||||||
|
Error("invalid pragma pack record");
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
FpPragmaCurrentValue = Record[0];
|
||||||
|
FpPragmaCurrentLocation = ReadSourceLocation(F, Record[1]);
|
||||||
|
unsigned NumStackEntries = Record[2];
|
||||||
|
unsigned Idx = 3;
|
||||||
|
// Reset the stack when importing a new module.
|
||||||
|
FpPragmaStack.clear();
|
||||||
|
for (unsigned I = 0; I < NumStackEntries; ++I) {
|
||||||
|
FpPragmaStackEntry Entry;
|
||||||
|
Entry.Value = Record[Idx++];
|
||||||
|
Entry.Location = ReadSourceLocation(F, Record[Idx++]);
|
||||||
|
Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]);
|
||||||
|
FpPragmaStrings.push_back(ReadString(Record, Idx));
|
||||||
|
Entry.SlotLabel = FpPragmaStrings.back();
|
||||||
|
FpPragmaStack.push_back(Entry);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DECLS_TO_CHECK_FOR_DEFERRED_DIAGS:
|
case DECLS_TO_CHECK_FOR_DEFERRED_DIAGS:
|
||||||
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
||||||
DeclsToCheckForDeferredDiags.push_back(getGlobalDeclID(F, Record[I]));
|
DeclsToCheckForDeferredDiags.push_back(getGlobalDeclID(F, Record[I]));
|
||||||
|
@ -7853,6 +7876,34 @@ void ASTReader::UpdateSema() {
|
||||||
SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation;
|
SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (FpPragmaCurrentValue) {
|
||||||
|
// The bottom of the stack might have a default value. It must be adjusted
|
||||||
|
// to the current value to ensure that fp-pragma state is preserved after
|
||||||
|
// popping entries that were included/imported from a PCH/module.
|
||||||
|
bool DropFirst = false;
|
||||||
|
if (!FpPragmaStack.empty() && FpPragmaStack.front().Location.isInvalid()) {
|
||||||
|
assert(FpPragmaStack.front().Value ==
|
||||||
|
SemaObj->FpPragmaStack.DefaultValue &&
|
||||||
|
"Expected a default pragma float_control value");
|
||||||
|
SemaObj->FpPragmaStack.Stack.emplace_back(
|
||||||
|
FpPragmaStack.front().SlotLabel, SemaObj->FpPragmaStack.CurrentValue,
|
||||||
|
SemaObj->FpPragmaStack.CurrentPragmaLocation,
|
||||||
|
FpPragmaStack.front().PushLocation);
|
||||||
|
DropFirst = true;
|
||||||
|
}
|
||||||
|
for (const auto &Entry :
|
||||||
|
llvm::makeArrayRef(FpPragmaStack).drop_front(DropFirst ? 1 : 0))
|
||||||
|
SemaObj->FpPragmaStack.Stack.emplace_back(
|
||||||
|
Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation);
|
||||||
|
if (FpPragmaCurrentLocation.isInvalid()) {
|
||||||
|
assert(*FpPragmaCurrentValue == SemaObj->FpPragmaStack.DefaultValue &&
|
||||||
|
"Expected a default pragma float_control value");
|
||||||
|
// Keep the current values.
|
||||||
|
} else {
|
||||||
|
SemaObj->FpPragmaStack.CurrentValue = *FpPragmaCurrentValue;
|
||||||
|
SemaObj->FpPragmaStack.CurrentPragmaLocation = FpPragmaCurrentLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentifierInfo *ASTReader::get(StringRef Name) {
|
IdentifierInfo *ASTReader::get(StringRef Name) {
|
||||||
|
|
|
@ -682,10 +682,14 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
|
||||||
|
|
||||||
void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
|
void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
|
||||||
VisitExpr(E);
|
VisitExpr(E);
|
||||||
|
bool hasFP_Features = Record.readInt();
|
||||||
|
assert(hasFP_Features == E->hasStoredFPFeatures());
|
||||||
E->setSubExpr(Record.readSubExpr());
|
E->setSubExpr(Record.readSubExpr());
|
||||||
E->setOpcode((UnaryOperator::Opcode)Record.readInt());
|
E->setOpcode((UnaryOperator::Opcode)Record.readInt());
|
||||||
E->setOperatorLoc(readSourceLocation());
|
E->setOperatorLoc(readSourceLocation());
|
||||||
E->setCanOverflow(Record.readInt());
|
E->setCanOverflow(Record.readInt());
|
||||||
|
if (hasFP_Features)
|
||||||
|
E->setStoredFPFeatures(FPOptions(Record.readInt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
|
void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
|
||||||
|
@ -2900,7 +2904,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_UNARY_OPERATOR:
|
case EXPR_UNARY_OPERATOR:
|
||||||
S = new (Context) UnaryOperator(Empty);
|
S = UnaryOperator::CreateEmpty(Context,
|
||||||
|
Record[ASTStmtReader::NumExprFields]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_OFFSETOF:
|
case EXPR_OFFSETOF:
|
||||||
|
|
|
@ -4139,6 +4139,26 @@ void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
|
||||||
Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
|
Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the state of 'pragma float_control' at the end of the module.
|
||||||
|
void ASTWriter::WriteFloatControlPragmaOptions(Sema &SemaRef) {
|
||||||
|
// Don't serialize pragma float_control state for modules,
|
||||||
|
// since it should only take effect on a per-submodule basis.
|
||||||
|
if (WritingModule)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RecordData Record;
|
||||||
|
Record.push_back(SemaRef.FpPragmaStack.CurrentValue);
|
||||||
|
AddSourceLocation(SemaRef.FpPragmaStack.CurrentPragmaLocation, Record);
|
||||||
|
Record.push_back(SemaRef.FpPragmaStack.Stack.size());
|
||||||
|
for (const auto &StackEntry : SemaRef.FpPragmaStack.Stack) {
|
||||||
|
Record.push_back(StackEntry.Value);
|
||||||
|
AddSourceLocation(StackEntry.PragmaLocation, Record);
|
||||||
|
AddSourceLocation(StackEntry.PragmaPushLocation, Record);
|
||||||
|
AddString(StackEntry.StackSlotLabel, Record);
|
||||||
|
}
|
||||||
|
Stream.EmitRecord(FLOAT_CONTROL_PRAGMA_OPTIONS, Record);
|
||||||
|
}
|
||||||
|
|
||||||
void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
|
void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
|
||||||
ModuleFileExtensionWriter &Writer) {
|
ModuleFileExtensionWriter &Writer) {
|
||||||
// Enter the extension block.
|
// Enter the extension block.
|
||||||
|
@ -4867,6 +4887,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
|
||||||
WriteMSPointersToMembersPragmaOptions(SemaRef);
|
WriteMSPointersToMembersPragmaOptions(SemaRef);
|
||||||
}
|
}
|
||||||
WritePackPragmaOptions(SemaRef);
|
WritePackPragmaOptions(SemaRef);
|
||||||
|
WriteFloatControlPragmaOptions(SemaRef);
|
||||||
|
|
||||||
// Some simple statistics
|
// Some simple statistics
|
||||||
RecordData::value_type Record[] = {
|
RecordData::value_type Record[] = {
|
||||||
|
|
|
@ -702,10 +702,16 @@ void ASTStmtWriter::VisitParenListExpr(ParenListExpr *E) {
|
||||||
|
|
||||||
void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
|
void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
|
||||||
VisitExpr(E);
|
VisitExpr(E);
|
||||||
|
bool HasFPFeatures = E->hasStoredFPFeatures();
|
||||||
|
// Write this first for easy access when deserializing, as they affect the
|
||||||
|
// size of the UnaryOperator.
|
||||||
|
Record.push_back(HasFPFeatures);
|
||||||
Record.AddStmt(E->getSubExpr());
|
Record.AddStmt(E->getSubExpr());
|
||||||
Record.push_back(E->getOpcode()); // FIXME: stable encoding
|
Record.push_back(E->getOpcode()); // FIXME: stable encoding
|
||||||
Record.AddSourceLocation(E->getOperatorLoc());
|
Record.AddSourceLocation(E->getOperatorLoc());
|
||||||
Record.push_back(E->canOverflow());
|
Record.push_back(E->canOverflow());
|
||||||
|
if (HasFPFeatures)
|
||||||
|
Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
|
||||||
Code = serialization::EXPR_UNARY_OPERATOR;
|
Code = serialization::EXPR_UNARY_OPERATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// REQUIRES: nvptx-registered-target
|
// REQUIRES: nvptx-registered-target
|
||||||
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_60 \
|
// RUN: %clang_cc1 -ffp-contract=off -triple nvptx-unknown-unknown -target-cpu sm_60 \
|
||||||
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
|
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
|
||||||
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP32 %s
|
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP32 %s
|
||||||
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -target-cpu sm_60 \
|
// RUN: %clang_cc1 -ffp-contract=off -triple nvptx64-unknown-unknown -target-cpu sm_60 \
|
||||||
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
|
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
|
||||||
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
|
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
|
||||||
// RUN: %clang_cc1 -triple nvptx64-unknown-unknown -target-cpu sm_61 \
|
// RUN: %clang_cc1 -ffp-contract=off -triple nvptx64-unknown-unknown -target-cpu sm_61 \
|
||||||
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
|
// RUN: -fcuda-is-device -S -emit-llvm -o - -x cuda %s \
|
||||||
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
|
// RUN: | FileCheck -check-prefix=CHECK -check-prefix=LP64 %s
|
||||||
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_53 \
|
// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_53 \
|
||||||
|
|
|
@ -154,9 +154,9 @@ void bar(float f) {
|
||||||
(double)f * f - f;
|
(double)f * f - f;
|
||||||
(long double)-f * f + f;
|
(long double)-f * f + f;
|
||||||
|
|
||||||
// CHECK: call float @llvm.experimental.constrained.fmuladd.f32
|
// CHECK: call contract float @llvm.experimental.constrained.fmuladd.f32
|
||||||
// CHECK: fneg
|
// CHECK: fneg
|
||||||
// CHECK: call double @llvm.experimental.constrained.fmuladd.f64
|
// CHECK: call contract double @llvm.experimental.constrained.fmuladd.f64
|
||||||
// CHECK: fneg
|
// CHECK: fneg
|
||||||
// CHECK: call x86_fp80 @llvm.experimental.constrained.fmuladd.f80
|
// CHECK: call contract x86_fp80 @llvm.experimental.constrained.fmuladd.f80
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s
|
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s
|
||||||
float f0, f1, f2;
|
float f0, f1, f2;
|
||||||
|
|
||||||
void foo(void) {
|
void foo(void) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// Is FP_CONTRACT honored in a simple case?
|
// Is FP_CONTRACT honored in a simple case?
|
||||||
float fp_contract_1(float a, float b, float c) {
|
float fp_contract_1(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_1fff
|
// CHECK: _Z13fp_contract_1fff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
#pragma clang fp contract(on)
|
#pragma clang fp contract(on)
|
||||||
return a * b + c;
|
return a * b + c;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ T template_muladd(T a, T b, T c) {
|
||||||
|
|
||||||
float fp_contract_3(float a, float b, float c) {
|
float fp_contract_3(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_3fff
|
// CHECK: _Z13fp_contract_3fff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
return template_muladd<float>(a, b, c);
|
return template_muladd<float>(a, b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ class fp_contract_4 {
|
||||||
|
|
||||||
template class fp_contract_4<int>;
|
template class fp_contract_4<int>;
|
||||||
// CHECK: _ZN13fp_contract_4IiE6methodEfff
|
// CHECK: _ZN13fp_contract_4IiE6methodEfff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
|
|
||||||
// Check file-scoped FP_CONTRACT
|
// Check file-scoped FP_CONTRACT
|
||||||
#pragma clang fp contract(on)
|
#pragma clang fp contract(on)
|
||||||
float fp_contract_5(float a, float b, float c) {
|
float fp_contract_5(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_5fff
|
// CHECK: _Z13fp_contract_5fff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
return a * b + c;
|
return a * b + c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ float fp_contract_6(float a, float b, float c) {
|
||||||
|
|
||||||
float fp_contract_7(float a, float b, float c) {
|
float fp_contract_7(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_7fff
|
// CHECK: _Z13fp_contract_7fff
|
||||||
// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
|
// CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
|
||||||
// CHECK-NEXT: fsub float %[[M]], %c
|
// CHECK-NEXT: fsub contract float %[[M]], %c
|
||||||
#pragma clang fp contract(on)
|
#pragma clang fp contract(on)
|
||||||
return (a = 2 * b) - c;
|
return (a = 2 * b) - c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
// Is FP_CONTRACT honored in a simple case?
|
// Is FP_CONTRACT honored in a simple case?
|
||||||
float fp_contract_1(float a, float b, float c) {
|
float fp_contract_1(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_1fff
|
// CHECK: _Z13fp_contract_1fff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
#pragma STDC FP_CONTRACT ON
|
#pragma STDC FP_CONTRACT ON
|
||||||
return a * b + c;
|
return a * b + c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ T template_muladd(T a, T b, T c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float fp_contract_3(float a, float b, float c) {
|
float fp_contract_3(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_3fff
|
// CHECK: _Z13fp_contract_3fff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
return template_muladd<float>(a, b, c);
|
return template_muladd<float>(a, b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,13 +44,13 @@ template<typename T> class fp_contract_4 {
|
||||||
|
|
||||||
template class fp_contract_4<int>;
|
template class fp_contract_4<int>;
|
||||||
// CHECK: _ZN13fp_contract_4IiE6methodEfff
|
// CHECK: _ZN13fp_contract_4IiE6methodEfff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
|
|
||||||
// Check file-scoped FP_CONTRACT
|
// Check file-scoped FP_CONTRACT
|
||||||
#pragma STDC FP_CONTRACT ON
|
#pragma STDC FP_CONTRACT ON
|
||||||
float fp_contract_5(float a, float b, float c) {
|
float fp_contract_5(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_5fff
|
// CHECK: _Z13fp_contract_5fff
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
return a * b + c;
|
return a * b + c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,25 +67,25 @@ float fp_contract_6(float a, float b, float c) {
|
||||||
// https://llvm.org/bugs/show_bug.cgi?id=25719
|
// https://llvm.org/bugs/show_bug.cgi?id=25719
|
||||||
|
|
||||||
float fp_contract_7(float a, float b, float c) {
|
float fp_contract_7(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_7fff
|
// CHECK: _Z13fp_contract_7fff
|
||||||
// CHECK: %[[M:.+]] = fmul float %b, 2.000000e+00
|
// CHECK: %[[M:.+]] = fmul contract float %b, 2.000000e+00
|
||||||
// CHECK-NEXT: fsub float %[[M]], %c
|
// CHECK-NEXT: fsub contract float %[[M]], %c
|
||||||
#pragma STDC FP_CONTRACT ON
|
#pragma STDC FP_CONTRACT ON
|
||||||
return (a = 2 * b) - c;
|
return (a = 2 * b) - c;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fp_contract_8(float a, float b, float c) {
|
float fp_contract_8(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_8fff
|
// CHECK: _Z13fp_contract_8fff
|
||||||
// CHECK: fneg float %c
|
// CHECK: fneg contract float %c
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
#pragma STDC FP_CONTRACT ON
|
#pragma STDC FP_CONTRACT ON
|
||||||
return a * b - c;
|
return a * b - c;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fp_contract_9(float a, float b, float c) {
|
float fp_contract_9(float a, float b, float c) {
|
||||||
// CHECK: _Z13fp_contract_9fff
|
// CHECK: _Z13fp_contract_9fff
|
||||||
// CHECK: fneg float %a
|
// CHECK: fneg contract float %a
|
||||||
// CHECK: tail call float @llvm.fmuladd
|
// CHECK: tail call contract float @llvm.fmuladd
|
||||||
#pragma STDC FP_CONTRACT ON
|
#pragma STDC FP_CONTRACT ON
|
||||||
return c - a * b;
|
return c - a * b;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// RUN: %clang_cc1 -ffp-contract=on -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
|
||||||
|
// RUN: %clang_cc1 -ffp-contract=on -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||||
|
// RUN: %clang_cc1 -ffp-contract=on -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
|
||||||
|
// Verify that float_control does not pertain to initializer expressions
|
||||||
|
|
||||||
|
float y();
|
||||||
|
float z();
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
class ON {
|
||||||
|
float w = 2 + y() * z();
|
||||||
|
// CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
|
||||||
|
//CHECK: call contract float {{.*}}llvm.fmuladd
|
||||||
|
};
|
||||||
|
ON on;
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
class OFF {
|
||||||
|
float w = 2 + y() * z();
|
||||||
|
// CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
|
||||||
|
//CHECK: call contract float {{.*}}llvm.fmuladd
|
||||||
|
};
|
||||||
|
OFF off;
|
|
@ -0,0 +1,47 @@
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||||
|
|
||||||
|
float fff(float x, float y) {
|
||||||
|
// CHECK-LABEL: define float @_Z3fffff{{.*}}
|
||||||
|
// CHECK: entry
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
float z;
|
||||||
|
z = z * z;
|
||||||
|
//CHECK: llvm.experimental.constrained.fmul{{.*}}
|
||||||
|
{
|
||||||
|
z = x * y;
|
||||||
|
//CHECK: llvm.experimental.constrained.fmul{{.*}}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// This pragma has no effect since if there are any fp intrin in the
|
||||||
|
// function then all the operations need to be fp intrin
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
z = z + x * y;
|
||||||
|
//CHECK: llvm.experimental.constrained.fmul{{.*}}
|
||||||
|
}
|
||||||
|
z = z * z;
|
||||||
|
//CHECK: llvm.experimental.constrained.fmul{{.*}}
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
float check_precise(float x, float y) {
|
||||||
|
// CHECK-LABEL: define float @_Z13check_preciseff{{.*}}
|
||||||
|
float z;
|
||||||
|
{
|
||||||
|
#pragma float_control(precise, on)
|
||||||
|
z = x * y + z;
|
||||||
|
//CHECK: llvm.fmuladd{{.*}}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
#pragma float_control(precise, off)
|
||||||
|
z = x * y + z;
|
||||||
|
//CHECK: fmul fast float
|
||||||
|
//CHECK: fadd fast float
|
||||||
|
}
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
float fma_test1(float a, float b, float c) {
|
||||||
|
// CHECK-LABEL define float @_Z9fma_test1fff{{.*}}
|
||||||
|
#pragma float_control(precise, on)
|
||||||
|
float x = a * b + c;
|
||||||
|
//CHECK: fmuladd
|
||||||
|
return x;
|
||||||
|
}
|
|
@ -0,0 +1,253 @@
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DDEFAULT=1 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DEBSTRICT=1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -DFAST=1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s
|
||||||
|
|
||||||
|
#define FUN(n) \
|
||||||
|
(float z) { return n * z + n; }
|
||||||
|
|
||||||
|
float fun_default FUN(1)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z11fun_defaultf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
// Note that backend wants constrained intrinsics used
|
||||||
|
// throughout the function if they are needed anywhere in the function.
|
||||||
|
// In that case, operations are built with constrained intrinsics operator
|
||||||
|
// but using default settings for exception behavior and rounding mode.
|
||||||
|
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(push)
|
||||||
|
#ifndef FAST
|
||||||
|
// Rule: precise must be enabled
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
#endif
|
||||||
|
float exc_on FUN(2)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z6exc_onf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: llvm.experimental.constrained.fmul{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: nnan ninf contract float {{.*}}llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//Not possible to enable float_control(except) in FAST mode.
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(pop)
|
||||||
|
float exc_pop FUN(5)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z7exc_popf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: llvm.experimental.constrained.fmuladd{{.*}}tonearest{{.*}}strict
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
float exc_off FUN(5)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z7exc_offf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: call contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: call contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(precise, on, push)
|
||||||
|
float precise_on FUN(3)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z10precise_onf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
// If precise is pushed then all fast-math should be off!
|
||||||
|
//CHECK-NOHONOR: call contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(pop)
|
||||||
|
float precise_pop FUN(3)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z11precise_popf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
#pragma float_control(precise, off)
|
||||||
|
float precise_off FUN(4)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z11precise_offf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
// Note: precise_off enables fp_contract=fast and the instructions
|
||||||
|
// generated do not include the contract flag, although it was enabled
|
||||||
|
// in IRBuilder.
|
||||||
|
//CHECK-DDEFAULT: fmul fast float
|
||||||
|
//CHECK-DDEFAULT: fadd fast float
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: fmul fast float
|
||||||
|
//CHECK-DEBSTRICT: fadd fast float
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
// fast math should be enabled, and contract should be fast
|
||||||
|
//CHECK-NOHONOR: fmul fast float
|
||||||
|
//CHECK-NOHONOR: fadd fast float
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(precise, on)
|
||||||
|
float precise_on2 FUN(3)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z11precise_on2f{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
// fast math should be off, and contract should be on
|
||||||
|
//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(push)
|
||||||
|
float precise_push FUN(3)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z12precise_pushf{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(precise, off)
|
||||||
|
float precise_off2 FUN(4)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z12precise_off2f{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: fmul fast float
|
||||||
|
//CHECK-DDEFAULT: fadd fast float
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: fmul fast float
|
||||||
|
//CHECK-DEBSTRICT: fadd fast float
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
// fast math settings since precise is off
|
||||||
|
//CHECK-NOHONOR: fmul fast float
|
||||||
|
//CHECK-NOHONOR: fadd fast float
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(pop)
|
||||||
|
float precise_pop2 FUN(3)
|
||||||
|
//CHECK-LABEL: define {{.*}} @_Z12precise_pop2f{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: contract float {{.*}}llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FAST
|
||||||
|
// Rule: precise must be enabled
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
#endif
|
||||||
|
float y();
|
||||||
|
class ON {
|
||||||
|
// Settings for top level class initializer revert to command line
|
||||||
|
// source pragma's do not pertain.
|
||||||
|
float z = 2 + y() * 7;
|
||||||
|
//CHECK-LABEL: define {{.*}} void @_ZN2ONC2Ev{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: call contract float {{.*}}llvm.fmuladd
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//Currently, same as default [command line options not considered]
|
||||||
|
//CHECK-DEBSTRICT: call contract float {{.*}}llvm.fmuladd
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
ON on;
|
||||||
|
#pragma float_control(except, off)
|
||||||
|
class OFF {
|
||||||
|
float w = 2 + y() * 7;
|
||||||
|
//CHECK-LABEL: define {{.*}} void @_ZN3OFFC2Ev{{.*}}
|
||||||
|
#if DEFAULT
|
||||||
|
//CHECK-DDEFAULT: call contract float {{.*}}llvm.fmuladd
|
||||||
|
#endif
|
||||||
|
#if EBSTRICT
|
||||||
|
//CHECK-DEBSTRICT: call contract float {{.*}}llvm.fmuladd
|
||||||
|
#endif
|
||||||
|
#if NOHONOR
|
||||||
|
//CHECK-NOHONOR: call nnan ninf contract float @llvm.fmuladd{{.*}}
|
||||||
|
#endif
|
||||||
|
#if FAST
|
||||||
|
//CHECK-FAST: fmul fast float
|
||||||
|
//CHECK-FAST: fadd fast float
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
OFF off;
|
|
@ -1,7 +1,7 @@
|
||||||
// RUN: %clang_cc1 -ftrapping-math -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
|
// RUN: %clang_cc1 -ftrapping-math -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
|
||||||
// RUN: %clang_cc1 -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
|
// RUN: %clang_cc1 -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
|
||||||
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
||||||
// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s -check-prefix=FASTNOCONTRACT
|
||||||
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
||||||
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
|
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
|
||||||
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
|
// RUN: %clang_cc1 -ffast-math -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
|
||||||
|
@ -17,6 +17,7 @@ void foo() {
|
||||||
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
||||||
// PRECISE: fadd contract float %{{.*}}, %{{.*}}
|
// PRECISE: fadd contract float %{{.*}}, %{{.*}}
|
||||||
// FAST: fadd fast
|
// FAST: fadd fast
|
||||||
|
// FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
|
||||||
f0 = f1 + f2;
|
f0 = f1 + f2;
|
||||||
|
|
||||||
// CHECK: ret
|
// CHECK: ret
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// RUN: %clang_cc1 -x c++ -ftrapping-math -fexceptions -fcxx-exceptions -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
|
// RUN: %clang_cc1 -x c++ -ftrapping-math -fexceptions -fcxx-exceptions -frounding-math -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=FPMODELSTRICT
|
||||||
// RUN: %clang_cc1 -x c++ -ffp-contract=fast -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
|
// RUN: %clang_cc1 -x c++ -ffp-contract=fast -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=PRECISE
|
||||||
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
||||||
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix=FASTNOCONTRACT
|
||||||
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=ignore -emit-llvm -o - %s | FileCheck %s -check-prefix=FAST
|
||||||
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
|
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s -check-prefix=EXCEPT
|
||||||
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
|
// RUN: %clang_cc1 -x c++ -ffast-math -fexceptions -fcxx-exceptions -ffp-contract=fast -ffp-exception-behavior=maytrap -emit-llvm -o - %s | FileCheck %s -check-prefix=MAYTRAP
|
||||||
|
@ -20,16 +20,17 @@ float f0, f1, f2;
|
||||||
// CHECK-LABEL: define {{.*}}void @_ZN4aaaaIiED2Ev{{.*}}
|
// CHECK-LABEL: define {{.*}}void @_ZN4aaaaIiED2Ev{{.*}}
|
||||||
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// MAYTRAP: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
|
// MAYTRAP: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
|
||||||
// EXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
|
// EXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
|
||||||
// FPMODELSTRICT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
// FPMODELSTRICT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
// STRICTEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
// STRICTEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
|
||||||
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
// STRICTNOEXCEPT: llvm.experimental.constrained.fadd.f32(float %{{.*}}, float %{{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
|
||||||
// PRECISE: fadd contract float %{{.*}}, %{{.*}}
|
// PRECISE: fadd contract float %{{.*}}, %{{.*}}
|
||||||
// FAST: fadd fast
|
// FAST: fadd fast
|
||||||
f0 = f1 + f2;
|
// FASTNOCONTRACT: fadd reassoc nnan ninf nsz arcp afn float
|
||||||
|
f0 = f1 + f2;
|
||||||
|
|
||||||
// CHECK: ret void
|
// CHECK: ret void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
float spscalardiv(float a, float b) {
|
float spscalardiv(float a, float b) {
|
||||||
// CHECK: @spscalardiv(
|
// CHECK: @spscalardiv(
|
||||||
|
|
||||||
// NORMAL: fdiv float
|
// NORMAL: fdiv contract float
|
||||||
// FAST: fdiv fast float
|
// FAST: fdiv fast float
|
||||||
// FINITE: fdiv nnan ninf float
|
// FINITE: fdiv nnan ninf contract float
|
||||||
// UNSAFE: fdiv nnan nsz float
|
// UNSAFE: fdiv nnan nsz contract float
|
||||||
// MAD: fdiv float
|
// MAD: fdiv contract float
|
||||||
// NOSIGNED: fdiv nsz float
|
// NOSIGNED: fdiv nsz contract float
|
||||||
return a / b;
|
return a / b;
|
||||||
}
|
}
|
||||||
// CHECK: attributes
|
// CHECK: attributes
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
|
// RUN: %clang_cc1 %s -cl-single-precision-constant -emit-llvm -o - | FileCheck %s
|
||||||
|
|
||||||
float fn(float f) {
|
float fn(float f) {
|
||||||
// CHECK: tail call float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
|
// CHECK: tail call contract float @llvm.fmuladd.f32(float %f, float 2.000000e+00, float 1.000000e+00)
|
||||||
return f*2. + 1.;
|
return f*2. + 1.;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// REQUIRES: nvptx-registered-target
|
// REQUIRES: nvptx-registered-target
|
||||||
// RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
|
// RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
|
||||||
// RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW
|
// RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW
|
||||||
// RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math
|
// RUN: %clang_cc1 -x c -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math -ffp-contract=fast
|
||||||
// RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math | FileCheck %s --check-prefix=FAST
|
// RUN: %clang_cc1 -x c -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math -ffp-contract=fast | FileCheck %s --check-prefix=FAST
|
||||||
// expected-no-diagnostics
|
// expected-no-diagnostics
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// REQUIRES: nvptx-registered-target
|
// REQUIRES: nvptx-registered-target
|
||||||
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
|
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc
|
||||||
// RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW
|
// RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=SLOW
|
||||||
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math
|
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include -fopenmp -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -ffast-math -ffp-contract=fast
|
||||||
// RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math | FileCheck %s --check-prefix=FAST
|
// RUN: %clang_cc1 -x c++ -include __clang_openmp_device_functions.h -internal-isystem %S/../../lib/Headers/openmp_wrappers -internal-isystem %S/Inputs/include -fopenmp -triple nvptx64-nvidia-cuda -aux-triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -ffast-math -ffp-contract=fast | FileCheck %s --check-prefix=FAST
|
||||||
// expected-no-diagnostics
|
// expected-no-diagnostics
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Test this without pch.
|
||||||
|
// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DSET
|
||||||
|
// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DPUSH
|
||||||
|
// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -DPUSH_POP
|
||||||
|
|
||||||
|
// 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 -DPUSH -emit-pch -o %t
|
||||||
|
// RUN: %clang_cc1 %s -DPUSH -verify -include-pch %t
|
||||||
|
// RUN: %clang_cc1 %s -DPUSH_POP -emit-pch -o %t
|
||||||
|
// RUN: %clang_cc1 %s -DPUSH_POP -verify -include-pch %t
|
||||||
|
|
||||||
|
#ifndef HEADER
|
||||||
|
#define HEADER
|
||||||
|
|
||||||
|
#ifdef SET
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PUSH
|
||||||
|
#pragma float_control(precise, on)
|
||||||
|
#pragma float_control(push)
|
||||||
|
#pragma float_control(precise, off)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PUSH_POP
|
||||||
|
#pragma float_control(precise, on, push)
|
||||||
|
#pragma float_control(push)
|
||||||
|
#pragma float_control(pop)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef SET
|
||||||
|
float fun(float a, float b) {
|
||||||
|
// CHECK-LABEL: define float @fun{{.*}}
|
||||||
|
//CHECK-EBSTRICT: llvm.experimental.constrained.fmul{{.*}}tonearest{{.*}}strict
|
||||||
|
//CHECK-EBSTRICT: llvm.experimental.constrained.fadd{{.*}}tonearest{{.*}}strict
|
||||||
|
return a * b + 2;
|
||||||
|
}
|
||||||
|
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
|
||||||
|
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PUSH
|
||||||
|
#pragma float_control(pop)
|
||||||
|
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PUSH_POP
|
||||||
|
#pragma float_control(pop)
|
||||||
|
#pragma float_control(pop) // expected-warning {{#pragma float_control(pop, ...) failed: stack empty}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //ifndef HEADER
|
|
@ -0,0 +1,60 @@
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DCHECK_ERROR %s -verify
|
||||||
|
|
||||||
|
float function_scope(float a) {
|
||||||
|
#pragma float_control(precise, on) junk // expected-warning {{extra tokens at end of '#pragma float_control' - ignored}}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CHECK_ERROR
|
||||||
|
#pragma float_control(push)
|
||||||
|
#pragma float_control(pop)
|
||||||
|
#pragma float_control(precise, on, push)
|
||||||
|
void check_stack() {
|
||||||
|
#pragma float_control(push) // expected-error {{can only appear at file scope}}
|
||||||
|
#pragma float_control(pop) // expected-error {{can only appear at file scope}}
|
||||||
|
#pragma float_control(precise, on, push) // expected-error {{can only appear at file scope}}
|
||||||
|
#pragma float_control(except, on, push) // expected-error {{can only appear at file scope}}
|
||||||
|
#pragma float_control(except, on, push, junk) // expected-error {{float_control is malformed}}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fdenormal-fp-math=preserve-sign,preserve-sign -ftrapping-math -fsyntax-only %s -DDEFAULT -verify
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only %s -ffp-contract=fast -DPRECISE -verify
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only %s -ftrapping-math -ffp-contract=off -frounding-math -ffp-exception-behavior=strict -DSTRICT -verify
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-linux-gnu -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -ffp-contract=fast -ffast-math -ffinite-math-only -fsyntax-only %s -DFAST -verify
|
||||||
|
double a = 0.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 // expected-error{{'#pragma STDC FENV_ACCESS ON' is illegal when precise is disabled}}
|
||||||
|
#else
|
||||||
|
#pragma STDC FENV_ACCESS ON // expected-warning{{pragma STDC FENV_ACCESS ON is not supported, ignoring pragma}}
|
||||||
|
#endif
|
||||||
|
#ifdef STRICT
|
||||||
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
||||||
|
#else
|
||||||
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when fenv_access is enabled}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma float_control(precise, on)
|
||||||
|
#pragma float_control(except, on) // OK
|
||||||
|
#ifndef STRICT
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
||||||
|
#endif
|
||||||
|
int main() {
|
||||||
|
#ifdef STRICT
|
||||||
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
||||||
|
#else
|
||||||
|
#pragma float_control(precise, off) // expected-error {{'#pragma float_control(precise, off)' is illegal when except is enabled}}
|
||||||
|
#endif
|
||||||
|
#pragma float_control(except, on)
|
||||||
|
// error: '#pragma float_control(except, on)' is illegal when precise is disabled
|
||||||
|
double x = b / a; // only used for fp flag setting
|
||||||
|
if (a == a) // only used for fp flag setting
|
||||||
|
return 0; //(int)x;
|
||||||
|
}
|
|
@ -244,6 +244,8 @@ public:
|
||||||
/// Get the flags to be applied to created floating point ops
|
/// Get the flags to be applied to created floating point ops
|
||||||
FastMathFlags getFastMathFlags() const { return FMF; }
|
FastMathFlags getFastMathFlags() const { return FMF; }
|
||||||
|
|
||||||
|
FastMathFlags &getFastMathFlags() { return FMF; }
|
||||||
|
|
||||||
/// Clear the fast-math flags.
|
/// Clear the fast-math flags.
|
||||||
void clearFastMathFlags() { FMF.clear(); }
|
void clearFastMathFlags() { FMF.clear(); }
|
||||||
|
|
||||||
|
@ -332,10 +334,16 @@ public:
|
||||||
IRBuilderBase &Builder;
|
IRBuilderBase &Builder;
|
||||||
FastMathFlags FMF;
|
FastMathFlags FMF;
|
||||||
MDNode *FPMathTag;
|
MDNode *FPMathTag;
|
||||||
|
bool IsFPConstrained;
|
||||||
|
fp::ExceptionBehavior DefaultConstrainedExcept;
|
||||||
|
RoundingMode DefaultConstrainedRounding;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FastMathFlagGuard(IRBuilderBase &B)
|
FastMathFlagGuard(IRBuilderBase &B)
|
||||||
: Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag) {}
|
: Builder(B), FMF(B.FMF), FPMathTag(B.DefaultFPMathTag),
|
||||||
|
IsFPConstrained(B.IsFPConstrained),
|
||||||
|
DefaultConstrainedExcept(B.DefaultConstrainedExcept),
|
||||||
|
DefaultConstrainedRounding(B.DefaultConstrainedRounding) {}
|
||||||
|
|
||||||
FastMathFlagGuard(const FastMathFlagGuard &) = delete;
|
FastMathFlagGuard(const FastMathFlagGuard &) = delete;
|
||||||
FastMathFlagGuard &operator=(const FastMathFlagGuard &) = delete;
|
FastMathFlagGuard &operator=(const FastMathFlagGuard &) = delete;
|
||||||
|
@ -343,6 +351,9 @@ public:
|
||||||
~FastMathFlagGuard() {
|
~FastMathFlagGuard() {
|
||||||
Builder.FMF = FMF;
|
Builder.FMF = FMF;
|
||||||
Builder.DefaultFPMathTag = FPMathTag;
|
Builder.DefaultFPMathTag = FPMathTag;
|
||||||
|
Builder.IsFPConstrained = IsFPConstrained;
|
||||||
|
Builder.DefaultConstrainedExcept = DefaultConstrainedExcept;
|
||||||
|
Builder.DefaultConstrainedRounding = DefaultConstrainedRounding;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue