forked from OSchip/llvm-project
[FPEnv] Partially implement #pragma STDC FENV_ROUND
This change implements pragma STDC FENV_ROUND, which is introduced by the extension to standard (TS 18661-1). The pragma is implemented only in frontend, it sets apprpriate state of FPOptions stored in Sema. Use of these bits in constant evaluation adn/or code generator is not in the scope of this change. Parser issues warning on unsuppored pragma when it encounteres pragma STDC FENV_ROUND, however it makes syntax checks and updates Sema state as if the pragma were supported. Primary purpose of the partial implementation is to facilitate development of non-default floating poin environment. Previously a developer cannot set non-default rounding mode in sources, this mades preparing tests for say constant evaluation substantially complicated. Differential Revision: https://reviews.llvm.org/D86921
This commit is contained in:
parent
f9ad112770
commit
a633da5391
|
@ -1136,6 +1136,12 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
|
|||
def warn_stdc_fenv_access_not_supported :
|
||||
Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">,
|
||||
InGroup<UnknownPragmas>;
|
||||
def warn_stdc_fenv_round_not_supported :
|
||||
Warning<"pragma STDC FENV_ROUND is not supported">,
|
||||
InGroup<UnknownPragmas>;
|
||||
def warn_stdc_unknown_rounding_mode : Warning<
|
||||
"invalid or unsupported rounding mode in '#pragma STDC FENV_ROUND' - ignored">,
|
||||
InGroup<IgnoredPragmas>;
|
||||
// - #pragma comment
|
||||
def err_pragma_comment_malformed : Error<
|
||||
"pragma comment requires parenthesized identifier and optional string">;
|
||||
|
|
|
@ -829,6 +829,11 @@ PRAGMA_ANNOTATION(pragma_fp_contract)
|
|||
// handles them.
|
||||
PRAGMA_ANNOTATION(pragma_fenv_access)
|
||||
|
||||
// Annotation for #pragma STDC FENV_ROUND
|
||||
// The lexer produces these so that they only take effect when the parser
|
||||
// handles them.
|
||||
PRAGMA_ANNOTATION(pragma_fenv_round)
|
||||
|
||||
// Annotation for #pragma float_control
|
||||
// The lexer produces these so that they only take effect when the parser
|
||||
// handles them.
|
||||
|
|
|
@ -202,7 +202,8 @@ class Parser : public CodeCompletionHandler {
|
|||
std::unique_ptr<PragmaHandler> UnrollAndJamHintHandler;
|
||||
std::unique_ptr<PragmaHandler> NoUnrollAndJamHintHandler;
|
||||
std::unique_ptr<PragmaHandler> FPHandler;
|
||||
std::unique_ptr<PragmaHandler> STDCFENVHandler;
|
||||
std::unique_ptr<PragmaHandler> STDCFenvAccessHandler;
|
||||
std::unique_ptr<PragmaHandler> STDCFenvRoundHandler;
|
||||
std::unique_ptr<PragmaHandler> STDCCXLIMITHandler;
|
||||
std::unique_ptr<PragmaHandler> STDCUnknownHandler;
|
||||
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
|
||||
|
@ -745,6 +746,10 @@ private:
|
|||
/// #pragma STDC FENV_ACCESS...
|
||||
void HandlePragmaFEnvAccess();
|
||||
|
||||
/// Handle the annotation token produced for
|
||||
/// #pragma STDC FENV_ROUND...
|
||||
void HandlePragmaFEnvRound();
|
||||
|
||||
/// Handle the annotation token produced for
|
||||
/// #pragma float_control
|
||||
void HandlePragmaFloatControl();
|
||||
|
|
|
@ -9749,7 +9749,7 @@ public:
|
|||
/// \#pragma STDC FENV_ACCESS
|
||||
void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled);
|
||||
|
||||
/// Called to set rounding mode for floating point operations.
|
||||
/// Called to set constant rounding mode for floating point operations.
|
||||
void setRoundingMode(SourceLocation Loc, llvm::RoundingMode);
|
||||
|
||||
/// Called to set exception behavior for floating point operations.
|
||||
|
|
|
@ -135,6 +135,14 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
|
|||
}
|
||||
};
|
||||
|
||||
/// Handler for "\#pragma STDC FENV_ROUND ...".
|
||||
struct PragmaSTDC_FENV_ROUNDHandler : public PragmaHandler {
|
||||
PragmaSTDC_FENV_ROUNDHandler() : PragmaHandler("FENV_ROUND") {}
|
||||
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||
Token &Tok) override;
|
||||
};
|
||||
|
||||
/// PragmaSTDC_UnknownHandler - "\#pragma STDC ...".
|
||||
struct PragmaSTDC_UnknownHandler : public PragmaHandler {
|
||||
PragmaSTDC_UnknownHandler() = default;
|
||||
|
@ -312,8 +320,11 @@ void Parser::initializePragmaHandlers() {
|
|||
FPContractHandler = std::make_unique<PragmaFPContractHandler>();
|
||||
PP.AddPragmaHandler("STDC", FPContractHandler.get());
|
||||
|
||||
STDCFENVHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>();
|
||||
PP.AddPragmaHandler("STDC", STDCFENVHandler.get());
|
||||
STDCFenvAccessHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>();
|
||||
PP.AddPragmaHandler("STDC", STDCFenvAccessHandler.get());
|
||||
|
||||
STDCFenvRoundHandler = std::make_unique<PragmaSTDC_FENV_ROUNDHandler>();
|
||||
PP.AddPragmaHandler("STDC", STDCFenvRoundHandler.get());
|
||||
|
||||
STDCCXLIMITHandler = std::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>();
|
||||
PP.AddPragmaHandler("STDC", STDCCXLIMITHandler.get());
|
||||
|
@ -485,8 +496,11 @@ void Parser::resetPragmaHandlers() {
|
|||
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
|
||||
FPContractHandler.reset();
|
||||
|
||||
PP.RemovePragmaHandler("STDC", STDCFENVHandler.get());
|
||||
STDCFENVHandler.reset();
|
||||
PP.RemovePragmaHandler("STDC", STDCFenvAccessHandler.get());
|
||||
STDCFenvAccessHandler.reset();
|
||||
|
||||
PP.RemovePragmaHandler("STDC", STDCFenvRoundHandler.get());
|
||||
STDCFenvRoundHandler.reset();
|
||||
|
||||
PP.RemovePragmaHandler("STDC", STDCCXLIMITHandler.get());
|
||||
STDCCXLIMITHandler.reset();
|
||||
|
@ -697,6 +711,14 @@ void Parser::HandlePragmaFEnvAccess() {
|
|||
Actions.ActOnPragmaFEnvAccess(PragmaLoc, IsEnabled);
|
||||
}
|
||||
|
||||
void Parser::HandlePragmaFEnvRound() {
|
||||
assert(Tok.is(tok::annot_pragma_fenv_round));
|
||||
auto RM = static_cast<llvm::RoundingMode>(
|
||||
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
|
||||
|
||||
SourceLocation PragmaLoc = ConsumeAnnotationToken();
|
||||
Actions.setRoundingMode(PragmaLoc, RM);
|
||||
}
|
||||
|
||||
StmtResult Parser::HandlePragmaCaptured()
|
||||
{
|
||||
|
@ -2929,6 +2951,56 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
|
|||
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
|
||||
}
|
||||
|
||||
void PragmaSTDC_FENV_ROUNDHandler::HandlePragma(Preprocessor &PP,
|
||||
PragmaIntroducer Introducer,
|
||||
Token &Tok) {
|
||||
Token PragmaName = Tok;
|
||||
SmallVector<Token, 1> TokenList;
|
||||
|
||||
PP.Lex(Tok);
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
|
||||
<< PragmaName.getIdentifierInfo()->getName();
|
||||
return;
|
||||
}
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
|
||||
auto RM =
|
||||
llvm::StringSwitch<llvm::RoundingMode>(II->getName())
|
||||
.Case("FE_TOWARDZERO", llvm::RoundingMode::TowardZero)
|
||||
.Case("FE_TONEAREST", llvm::RoundingMode::NearestTiesToEven)
|
||||
.Case("FE_UPWARD", llvm::RoundingMode::TowardPositive)
|
||||
.Case("FE_DOWNWARD", llvm::RoundingMode::TowardNegative)
|
||||
.Case("FE_TONEARESTFROMZERO", llvm::RoundingMode::NearestTiesToAway)
|
||||
.Case("FE_DYNAMIC", llvm::RoundingMode::Dynamic)
|
||||
.Default(llvm::RoundingMode::Invalid);
|
||||
if (RM == llvm::RoundingMode::Invalid) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_stdc_unknown_rounding_mode);
|
||||
return;
|
||||
}
|
||||
PP.Lex(Tok);
|
||||
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
<< "STDC FENV_ROUND";
|
||||
return;
|
||||
}
|
||||
|
||||
// Until the pragma is fully implemented, issue a warning.
|
||||
PP.Diag(Tok.getLocation(), diag::warn_stdc_fenv_round_not_supported);
|
||||
|
||||
MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
|
||||
1);
|
||||
Toks[0].startToken();
|
||||
Toks[0].setKind(tok::annot_pragma_fenv_round);
|
||||
Toks[0].setLocation(Tok.getLocation());
|
||||
Toks[0].setAnnotationEndLoc(Tok.getLocation());
|
||||
Toks[0].setAnnotationValue(
|
||||
reinterpret_cast<void *>(static_cast<uintptr_t>(RM)));
|
||||
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
|
||||
/*IsReinject=*/false);
|
||||
}
|
||||
|
||||
void Parser::HandlePragmaFP() {
|
||||
assert(Tok.is(tok::annot_pragma_fp));
|
||||
auto *AnnotValue =
|
||||
|
|
|
@ -369,6 +369,12 @@ Retry:
|
|||
HandlePragmaFEnvAccess();
|
||||
return StmtEmpty();
|
||||
|
||||
case tok::annot_pragma_fenv_round:
|
||||
ProhibitAttributes(Attrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC FENV_ROUND";
|
||||
ConsumeAnnotationToken();
|
||||
return StmtError();
|
||||
|
||||
case tok::annot_pragma_float_control:
|
||||
ProhibitAttributes(Attrs);
|
||||
Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control";
|
||||
|
@ -943,6 +949,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
|
|||
case tok::annot_pragma_fenv_access:
|
||||
HandlePragmaFEnvAccess();
|
||||
break;
|
||||
case tok::annot_pragma_fenv_round:
|
||||
HandlePragmaFEnvRound();
|
||||
break;
|
||||
case tok::annot_pragma_float_control:
|
||||
HandlePragmaFloatControl();
|
||||
break;
|
||||
|
|
|
@ -783,6 +783,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
|
|||
case tok::annot_pragma_fenv_access:
|
||||
HandlePragmaFEnvAccess();
|
||||
return nullptr;
|
||||
case tok::annot_pragma_fenv_round:
|
||||
HandlePragmaFEnvRound();
|
||||
return nullptr;
|
||||
case tok::annot_pragma_float_control:
|
||||
HandlePragmaFloatControl();
|
||||
return nullptr;
|
||||
|
|
|
@ -979,6 +979,11 @@ void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
|
|||
}
|
||||
|
||||
void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
|
||||
// C2x: 7.6.2p3 If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off",
|
||||
// the translator may assume that the default rounding mode is in effect.
|
||||
if (FPR == llvm::RoundingMode::Dynamic && !CurFPFeatures.getAllowFEnvAccess())
|
||||
FPR = llvm::RoundingMode::NearestTiesToEven;
|
||||
|
||||
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
|
||||
NewFPFeatures.setRoundingModeOverride(FPR);
|
||||
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
|
||||
|
|
|
@ -34,4 +34,69 @@ float func_03(float x) {
|
|||
// CHECK-NEXT: ParmVarDecl {{.*}} x 'float'
|
||||
// CHECK-NEXT: CompoundStmt
|
||||
// CHECK-NEXT: ReturnStmt
|
||||
// CHECK-NEXT: CallExpr {{.*}} FPContractMode=0
|
||||
// CHECK-NEXT: CallExpr {{.*}} FPContractMode=0
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma STDC FENV_ROUND FE_DOWNWARD
|
||||
|
||||
float func_10(float x, float y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: FunctionDecl {{.*}} func_10 'float (float, float)'
|
||||
// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=3
|
||||
|
||||
float func_11(float x, float y) {
|
||||
if (x < 0) {
|
||||
#pragma STDC FENV_ROUND FE_UPWARD
|
||||
return x + y;
|
||||
}
|
||||
return x - y;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: FunctionDecl {{.*}} func_11 'float (float, float)'
|
||||
// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=2
|
||||
// CHECK: BinaryOperator {{.*}} 'float' '-' RoundingMode=3
|
||||
|
||||
|
||||
#pragma STDC FENV_ROUND FE_DYNAMIC
|
||||
|
||||
float func_12(float x, float y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: FunctionDecl {{.*}} func_12 'float (float, float)'
|
||||
// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=1
|
||||
|
||||
#pragma STDC FENV_ROUND FE_TONEAREST
|
||||
|
||||
float func_13(float x, float y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: FunctionDecl {{.*}} func_13 'float (float, float)'
|
||||
// CHECK: BinaryOperator {{.*}} 'float' '+' RoundingMode=1
|
||||
|
||||
|
||||
template <typename T>
|
||||
T func_14(T x, T y) {
|
||||
#pragma STDC FENV_ROUND FE_TOWARDZERO
|
||||
return x + y;
|
||||
}
|
||||
|
||||
float func_15(float x, float y) {
|
||||
#pragma STDC FPENV_ROUND FE_DOWNWARD
|
||||
return func_14(x, y);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: FunctionTemplateDecl {{.*}} func_14
|
||||
// CHECK: FunctionDecl {{.*}} func_14 'T (T, T)'
|
||||
// CHECK: CompoundStmt
|
||||
// CHECK-NEXT: ReturnStmt
|
||||
// CHECK-NEXT: BinaryOperator {{.*}} '+' RoundingMode=0
|
||||
// CHECK: FunctionDecl {{.*}} func_14 'float (float, float)'
|
||||
// CHECK: CompoundStmt
|
||||
// CHECK-NEXT: ReturnStmt
|
||||
// CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' RoundingMode=0
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Wignored-pragmas -verify %s
|
||||
|
||||
#pragma STDC FENV_ROUND ON // expected-warning {{invalid or unsupported rounding mode}}
|
||||
|
||||
float func_01(int x, float y) {
|
||||
if (x)
|
||||
return y + 2;
|
||||
#pragma STDC FENV_ROUND FE_DOWNWARD // expected-error{{'#pragma STDC FENV_ROUND' can only appear at file scope or at the start of a compound statement}}
|
||||
// expected-warning@-1{{pragma STDC FENV_ROUND is not supported}}
|
||||
return x + y;
|
||||
}
|
Loading…
Reference in New Issue