This revision was automatically updated to reflect the committed changes. Closed by commit rGa633da5391b0: [FPEnv] Partially implement #pragma STDC FENV_ROUND (authored by sepavloff).
Changed prior to commit: https://reviews.llvm.org/D86921?vs=289110&id=289901#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D86921/new/ https://reviews.llvm.org/D86921 Files: clang/include/clang/Basic/DiagnosticParseKinds.td clang/include/clang/Basic/TokenKinds.def clang/include/clang/Parse/Parser.h clang/include/clang/Sema/Sema.h clang/lib/Parse/ParsePragma.cpp clang/lib/Parse/ParseStmt.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/SemaAttr.cpp clang/test/AST/ast-dump-fpfeatures.cpp clang/test/Parser/pragma-fenv_round.c
Index: clang/test/Parser/pragma-fenv_round.c =================================================================== --- /dev/null +++ clang/test/Parser/pragma-fenv_round.c @@ -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; +} Index: clang/test/AST/ast-dump-fpfeatures.cpp =================================================================== --- clang/test/AST/ast-dump-fpfeatures.cpp +++ clang/test/AST/ast-dump-fpfeatures.cpp @@ -34,4 +34,69 @@ // 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 Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -979,6 +979,11 @@ } 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); Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -783,6 +783,9 @@ 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; Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -369,6 +369,12 @@ 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 @@ case tok::annot_pragma_fenv_access: HandlePragmaFEnvAccess(); break; + case tok::annot_pragma_fenv_round: + HandlePragmaFEnvRound(); + break; case tok::annot_pragma_float_control: HandlePragmaFloatControl(); break; Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -135,6 +135,14 @@ } }; +/// 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 @@ 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 @@ 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 @@ 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 @@ /*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 = Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -9749,7 +9749,7 @@ /// \#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. Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -202,7 +202,8 @@ 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 @@ /// #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(); Index: clang/include/clang/Basic/TokenKinds.def =================================================================== --- clang/include/clang/Basic/TokenKinds.def +++ clang/include/clang/Basic/TokenKinds.def @@ -829,6 +829,11 @@ // 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. Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1136,6 +1136,12 @@ 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">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits