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">;
// 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.
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;
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();
/// \#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.
}
};
+/// 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;
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());
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();
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()
{
/*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 =
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";
case tok::annot_pragma_fenv_access:
HandlePragmaFEnvAccess();
break;
+ case tok::annot_pragma_fenv_round:
+ HandlePragmaFEnvRound();
+ break;
case tok::annot_pragma_float_control:
HandlePragmaFloatControl();
break;
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;
}
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);
// CHECK-NEXT: ParmVarDecl {{.*}} x 'float'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: CallExpr {{.*}} FPContractMode=0
\ No newline at end of file
+// 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
--- /dev/null
+// 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;
+}