Add option 'exceptions' to pragma clang fp
Pragma 'clang fp' is extended to support a new option, 'exceptions'. It allows to specify floating point exception behavior more flexibly. Differential Revision: https://reviews.llvm.org/D89849
This commit is contained in:
parent
27f647d117
commit
6021cbea4d
|
@ -3182,7 +3182,7 @@ The pragma can take two values: ``on`` and ``off``.
|
|||
float f(float x, float y, float z)
|
||||
{
|
||||
// Enable floating point reassociation across statements
|
||||
#pragma fp reassociate(on)
|
||||
#pragma clang fp reassociate(on)
|
||||
float t = x + y;
|
||||
float v = t + z;
|
||||
}
|
||||
|
@ -3211,6 +3211,31 @@ 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
|
||||
enabled for the translation unit with the ``-ffp-contract=fast`` flag.
|
||||
|
||||
|
||||
``#pragma clang fp exceptions`` specifies floating point exception behavior. It
|
||||
may take one the the values: ``ignore``, ``maytrap`` or ``strict``. Meaning of
|
||||
these values is same as for `constrained floating point intrinsics <http://llvm.org/docs/LangRef.html#constrained-floating-point-intrinsics>`_.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
{
|
||||
// Preserve floating point exceptions
|
||||
#pragma clang fp exceptions(strict)
|
||||
z = x + y;
|
||||
if (fetestexcept(FE_OVERFLOW))
|
||||
...
|
||||
}
|
||||
|
||||
A ``#pragma clang fp`` pragma may contain any number of options:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void func(float *dest, float a, float b) {
|
||||
#pragma clang fp exceptions(maytrap) contract(fast) reassociate(on)
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
|
|
@ -1388,12 +1388,13 @@ def err_pragma_loop_invalid_option : Error<
|
|||
"pipeline, pipeline_initiation_interval, vectorize_predicate, or distribute">;
|
||||
|
||||
def err_pragma_fp_invalid_option : Error<
|
||||
"%select{invalid|missing}0 option%select{ %1|}0; expected 'contract' or 'reassociate'">;
|
||||
"%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 'reassociate' or 'exceptions'">;
|
||||
def err_pragma_fp_invalid_argument : Error<
|
||||
"unexpected argument '%0' to '#pragma clang fp %1'; "
|
||||
"unexpected argument '%0' to '#pragma clang fp %1'; expected "
|
||||
"%select{"
|
||||
"expected 'fast' or 'on' or 'off'|"
|
||||
"expected 'on' or 'off'}2">;
|
||||
"'fast' or 'on' or 'off'|"
|
||||
"'on' or 'off'|"
|
||||
"'ignore', 'maytrap' or 'strict'}2">;
|
||||
|
||||
def err_pragma_invalid_keyword : Error<
|
||||
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
|
||||
|
|
|
@ -9896,6 +9896,10 @@ public:
|
|||
/// \#pragma STDC FENV_ACCESS
|
||||
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
|
||||
|
||||
/// Called on well formed '\#pragma clang fp' that has option 'exceptions'.
|
||||
void ActOnPragmaFPExceptions(SourceLocation Loc,
|
||||
LangOptions::FPExceptionModeKind);
|
||||
|
||||
/// Called to set constant rounding mode for floating point operations.
|
||||
void setRoundingMode(SourceLocation Loc, llvm::RoundingMode);
|
||||
|
||||
|
|
|
@ -2858,11 +2858,12 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
|
|||
namespace {
|
||||
/// Used as the annotation value for tok::annot_pragma_fp.
|
||||
struct TokFPAnnotValue {
|
||||
enum FlagKinds { Contract, Reassociate };
|
||||
enum FlagKinds { Contract, Reassociate, Exceptions };
|
||||
enum FlagValues { On, Off, Fast };
|
||||
|
||||
FlagKinds FlagKind;
|
||||
FlagValues FlagValue;
|
||||
llvm::Optional<LangOptions::FPModeKind> ContractValue;
|
||||
llvm::Optional<LangOptions::FPModeKind> ReassociateValue;
|
||||
llvm::Optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -2879,6 +2880,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
|||
return;
|
||||
}
|
||||
|
||||
auto *AnnotValue = new (PP.getPreprocessorAllocator()) TokFPAnnotValue;
|
||||
while (Tok.is(tok::identifier)) {
|
||||
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
|
||||
|
||||
|
@ -2887,6 +2889,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
|||
OptionInfo->getName())
|
||||
.Case("contract", TokFPAnnotValue::Contract)
|
||||
.Case("reassociate", TokFPAnnotValue::Reassociate)
|
||||
.Case("exceptions", TokFPAnnotValue::Exceptions)
|
||||
.Default(None);
|
||||
if (!FlagKind) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
|
||||
|
@ -2905,25 +2908,49 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
|||
if (Tok.isNot(tok::identifier)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << OptionInfo->getName()
|
||||
<< (FlagKind == TokFPAnnotValue::Reassociate);
|
||||
<< static_cast<int>(*FlagKind);
|
||||
return;
|
||||
}
|
||||
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
|
||||
auto FlagValue =
|
||||
llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
|
||||
II->getName())
|
||||
.Case("on", TokFPAnnotValue::On)
|
||||
.Case("off", TokFPAnnotValue::Off)
|
||||
.Case("fast", TokFPAnnotValue::Fast)
|
||||
.Default(llvm::None);
|
||||
|
||||
if (!FlagValue || (FlagKind == TokFPAnnotValue::Reassociate &&
|
||||
FlagValue == TokFPAnnotValue::Fast)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << OptionInfo->getName()
|
||||
<< (FlagKind == TokFPAnnotValue::Reassociate);
|
||||
return;
|
||||
if (FlagKind == TokFPAnnotValue::Contract) {
|
||||
AnnotValue->ContractValue =
|
||||
llvm::StringSwitch<llvm::Optional<LangOptions::FPModeKind>>(
|
||||
II->getName())
|
||||
.Case("on", LangOptions::FPModeKind::FPM_On)
|
||||
.Case("off", LangOptions::FPModeKind::FPM_Off)
|
||||
.Case("fast", LangOptions::FPModeKind::FPM_Fast)
|
||||
.Default(llvm::None);
|
||||
if (!AnnotValue->ContractValue) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
|
||||
return;
|
||||
}
|
||||
} else if (FlagKind == TokFPAnnotValue::Reassociate) {
|
||||
AnnotValue->ReassociateValue =
|
||||
llvm::StringSwitch<llvm::Optional<LangOptions::FPModeKind>>(
|
||||
II->getName())
|
||||
.Case("on", LangOptions::FPModeKind::FPM_On)
|
||||
.Case("off", LangOptions::FPModeKind::FPM_Off)
|
||||
.Default(llvm::None);
|
||||
if (!AnnotValue->ReassociateValue) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
|
||||
return;
|
||||
}
|
||||
} else if (FlagKind == TokFPAnnotValue::Exceptions) {
|
||||
AnnotValue->ExceptionsValue =
|
||||
llvm::StringSwitch<llvm::Optional<LangOptions::FPExceptionModeKind>>(
|
||||
II->getName())
|
||||
.Case("ignore", LangOptions::FPE_Ignore)
|
||||
.Case("maytrap", LangOptions::FPE_MayTrap)
|
||||
.Case("strict", LangOptions::FPE_Strict)
|
||||
.Default(llvm::None);
|
||||
if (!AnnotValue->ExceptionsValue) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
|
||||
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
|
||||
return;
|
||||
}
|
||||
}
|
||||
PP.Lex(Tok);
|
||||
|
||||
|
@ -2933,17 +2960,6 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
|||
return;
|
||||
}
|
||||
PP.Lex(Tok);
|
||||
|
||||
auto *AnnotValue = new (PP.getPreprocessorAllocator())
|
||||
TokFPAnnotValue{*FlagKind, *FlagValue};
|
||||
// Generate the fp annotation token.
|
||||
Token FPTok;
|
||||
FPTok.startToken();
|
||||
FPTok.setKind(tok::annot_pragma_fp);
|
||||
FPTok.setLocation(PragmaName.getLocation());
|
||||
FPTok.setAnnotationEndLoc(PragmaName.getLocation());
|
||||
FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
|
||||
TokenList.push_back(FPTok);
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
|
@ -2952,6 +2968,14 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
|||
return;
|
||||
}
|
||||
|
||||
Token FPTok;
|
||||
FPTok.startToken();
|
||||
FPTok.setKind(tok::annot_pragma_fp);
|
||||
FPTok.setLocation(PragmaName.getLocation());
|
||||
FPTok.setAnnotationEndLoc(PragmaName.getLocation());
|
||||
FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
|
||||
TokenList.push_back(FPTok);
|
||||
|
||||
auto TokenArray = std::make_unique<Token[]>(TokenList.size());
|
||||
std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
|
||||
|
||||
|
@ -3019,24 +3043,16 @@ void Parser::HandlePragmaFP() {
|
|||
auto *AnnotValue =
|
||||
reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
|
||||
|
||||
if (AnnotValue->FlagKind == TokFPAnnotValue::Reassociate)
|
||||
Actions.ActOnPragmaFPReassociate(
|
||||
Tok.getLocation(), AnnotValue->FlagValue == TokFPAnnotValue::On);
|
||||
else {
|
||||
LangOptions::FPModeKind FPC;
|
||||
switch (AnnotValue->FlagValue) {
|
||||
case TokFPAnnotValue::Off:
|
||||
FPC = LangOptions::FPM_Off;
|
||||
break;
|
||||
case TokFPAnnotValue::On:
|
||||
FPC = LangOptions::FPM_On;
|
||||
break;
|
||||
case TokFPAnnotValue::Fast:
|
||||
FPC = LangOptions::FPM_Fast;
|
||||
break;
|
||||
}
|
||||
Actions.ActOnPragmaFPContract(Tok.getLocation(), FPC);
|
||||
}
|
||||
if (AnnotValue->ReassociateValue)
|
||||
Actions.ActOnPragmaFPReassociate(Tok.getLocation(),
|
||||
*AnnotValue->ReassociateValue ==
|
||||
LangOptions::FPModeKind::FPM_On);
|
||||
if (AnnotValue->ContractValue)
|
||||
Actions.ActOnPragmaFPContract(Tok.getLocation(),
|
||||
*AnnotValue->ContractValue);
|
||||
if (AnnotValue->ExceptionsValue)
|
||||
Actions.ActOnPragmaFPExceptions(Tok.getLocation(),
|
||||
*AnnotValue->ExceptionsValue);
|
||||
ConsumeAnnotationToken();
|
||||
}
|
||||
|
||||
|
|
|
@ -1022,6 +1022,11 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
|
|||
CurFPFeatures = NewFPFeatures.applyOverrides(LO);
|
||||
}
|
||||
|
||||
void Sema::ActOnPragmaFPExceptions(SourceLocation Loc,
|
||||
LangOptions::FPExceptionModeKind FPE) {
|
||||
setExceptionMode(Loc, FPE);
|
||||
}
|
||||
|
||||
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
|
||||
SourceLocation Loc) {
|
||||
// Visibility calculations will consider the namespace's visibility.
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEF %s
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
|
||||
|
||||
float func_01(float x, float y, float z) {
|
||||
float res = x + y;
|
||||
{
|
||||
#pragma clang fp exceptions(maytrap)
|
||||
res += z;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
// CHECK-DEF-LABEL: @_Z7func_01fff
|
||||
// CHECK-DEF: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
|
||||
// CHECK-DEF: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
|
||||
|
||||
// CHECK-STRICT-LABEL: @_Z7func_01fff
|
||||
// CHECK-STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
|
||||
// CHECK-STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, metadata !"round.tonearest", metadata !"fpexcept.maytrap")
|
|
@ -1,14 +1,14 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||
|
||||
void test_0(int *List, int Length) {
|
||||
/* expected-error@+1 {{missing option; expected 'contract' or 'reassociate'}} */
|
||||
/* expected-error@+1 {{missing option; expected 'contract', 'reassociate' or 'exceptions'}} */
|
||||
#pragma clang fp
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
void test_1(int *List, int Length) {
|
||||
/* expected-error@+1 {{invalid option 'blah'; expected 'contract' or 'reassociate'}} */
|
||||
/* expected-error@+1 {{invalid option 'blah'; expected 'contract', 'reassociate' or 'exceptions'}} */
|
||||
#pragma clang fp blah
|
||||
for (int i = 0; i < Length; i++) {
|
||||
List[i] = i;
|
||||
|
@ -62,3 +62,14 @@ void test_8(int *List, int Length) {
|
|||
#pragma clang fp contract(fast)
|
||||
}
|
||||
}
|
||||
|
||||
void test_9(float *dest, float a, float b) {
|
||||
/* expected-error@+1 {{unexpected argument 'on' to '#pragma clang fp exceptions'; expected 'ignore', 'maytrap' or 'strict'}} */
|
||||
#pragma clang fp exceptions(on)
|
||||
*dest = a + b;
|
||||
}
|
||||
|
||||
void test_10(float *dest, float a, float b) {
|
||||
#pragma clang fp exceptions(maytrap) contract(fast) reassociate(on)
|
||||
*dest = a + b;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue