jcranmer-intel created this revision. Herald added a subscriber: dexonsmith. jcranmer-intel requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This pragma is defined in the C specification. Notably, the C specification makes the "DEFAULT" value identical to "OFF" for this pragma, unlike other floating-point pragmas which are undefined behavior. This may be surprising to some users. This patch builds on, and requires, the complex intrinsics to make the pragmas work properly. Depends on D119290 <https://reviews.llvm.org/D119290> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D119291 Files: clang/include/clang/Basic/TokenKinds.def clang/include/clang/Parse/Parser.h clang/include/clang/Sema/Sema.h clang/lib/Lex/Pragma.cpp clang/lib/Parse/ParsePragma.cpp clang/lib/Parse/ParseStmt.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/SemaAttr.cpp clang/test/CodeGen/cx-limited-range-pragma.c
Index: clang/test/CodeGen/cx-limited-range-pragma.c =================================================================== --- /dev/null +++ clang/test/CodeGen/cx-limited-range-pragma.c @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=limited -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-LIMITED +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=nonan -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-NO-NAN +// RUN: %clang_cc1 %s -O0 -emit-llvm -triple x86_64-unknown-unknown -fuse-complex-intrinsics -fcx-range=full -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-FULL + +_Complex float range_limited(_Complex float a, _Complex float b) { +// CHECK-COMMON: @range_limited +// CHECK-COMMON: call{{.*}}complex.fmul{{.*}} #[[LIMITED:[0-9]+]] +// CHECK-COMMON: call{{.*}}complex.fdiv{{.*}} #[[LIMITED]] +#pragma STDC CX_LIMITED_RANGE ON + return a * b + a / b; +} + +_Complex float range_full(_Complex float a, _Complex float b) { +// CHECK-COMMON: @range_full +// CHECK-COMMON: call{{.*}}complex.fmul{{.*}} #[[FULL:[0-9]+]] +// CHECK-COMMON: call{{.*}}complex.fdiv{{.*}} #[[FULL]] +#pragma STDC CX_LIMITED_RANGE OFF + return a * b + a / b; +} + +_Complex float range_default(_Complex float a, _Complex float b) { +// CHECK-LIMITED: @range_default +// CHECK-LIMITED: call{{.*}}complex.fmul{{.*}} #[[LIMITED]] +// CHECK-LIMITED: call{{.*}}complex.fdiv{{.*}} #[[LIMITED]] +// CHECK-NO-NAN: @range_default +// CHECK-NO-NAN: call{{.*}}complex.fmul{{.*}} #[[LIMITED]] +// CHECK-NO-NAN: call{{.*}}complex.fdiv{{.*}} #[[NONAN:[0-9]+]] +// CHECK-FULL: @range_default +// CHECK-FULL: call{{.*}}complex.fmul{{.*}} #[[FULL]] +// CHECK-FULL: call{{.*}}complex.fdiv{{.*}} #[[FULL]] + return a * b + a / b; +} + +_Complex float range_scoped(_Complex float a, _Complex float b) { +// CHECK-COMMON: @range_scoped +// CHECK-COMMON: call{{.*}}complex.fmul{{.*}} #[[FULL]] +// CHECK-COMMON: call{{.*}}complex.fdiv{{.*}} #[[FULL]] +#pragma STDC CX_LIMITED_RANGE OFF + _Complex float res = a * b; + { +#pragma STDC CX_LIMITED_RANGE DEFAULT + res += a / b; + } + return res; +} + +// CHECK-COMMON: attributes #[[LIMITED]] = { "complex-range"="limited" } +// CHECK-COMMON: attributes #[[FULL]] = { "complex-range"="full" } +// CHECK-NO-NAN: attributes #[[NONAN]] = { "complex-range"="no-nan" } Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -1165,6 +1165,14 @@ CurFPFeatures = NewFPFeatures.applyOverrides(LO); } +void Sema::ActOnPragmaComplexLimitedRange(SourceLocation Loc, + LangOptions::ComplexRangeKind Range) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + NewFPFeatures.setComplexRangeOverride(Range); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); +} + void Sema::ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind FPE) { setExceptionMode(Loc, FPE); Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -791,6 +791,9 @@ case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); return nullptr; + case tok::annot_pragma_cx_limited_range: + HandlePragmaComplexLimitedRange(); + 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 @@ -388,6 +388,12 @@ ConsumeAnnotationToken(); return StmtError(); + case tok::annot_pragma_cx_limited_range: + ProhibitAttributes(Attrs); + Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC CX_LIMITED_RANGE"; + ConsumeAnnotationToken(); + return StmtError(); + case tok::annot_pragma_float_control: ProhibitAttributes(Attrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control"; @@ -964,6 +970,9 @@ case tok::annot_pragma_fenv_round: HandlePragmaFEnvRound(); break; + case tok::annot_pragma_cx_limited_range: + HandlePragmaComplexLimitedRange(); + 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,7 +135,19 @@ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { tok::OnOffSwitch OOS; - PP.LexOnOffSwitch(OOS); + if (PP.LexOnOffSwitch(OOS)) + return; + + MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), + 1); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_cx_limited_range); + Toks[0].setLocation(Tok.getLocation()); + Toks[0].setAnnotationEndLoc(Tok.getLocation()); + Toks[0].setAnnotationValue(reinterpret_cast<void*>( + static_cast<uintptr_t>(OOS))); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); } }; @@ -799,6 +811,30 @@ Actions.setRoundingMode(PragmaLoc, RM); } +void Parser::HandlePragmaComplexLimitedRange() { + assert(Tok.is(tok::annot_pragma_cx_limited_range)); + tok::OnOffSwitch OOS = + static_cast<tok::OnOffSwitch>( + reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + + LangOptions::ComplexRangeKind Range; + switch (OOS) { + case tok::OOS_ON: + Range = LangOptions::CX_Limited; + break; + case tok::OOS_OFF: + Range = LangOptions::CX_Full; + break; + case tok::OOS_DEFAULT: + // Section 7.3.4 says the default is "OFF" here, not implementation-defined. + Range = LangOptions::CX_Full; + break; + } + + SourceLocation PragmaLoc = ConsumeAnnotationToken(); + Actions.ActOnPragmaComplexLimitedRange(PragmaLoc, Range); +} + StmtResult Parser::HandlePragmaCaptured() { assert(Tok.is(tok::annot_pragma_captured)); Index: clang/lib/Lex/Pragma.cpp =================================================================== --- clang/lib/Lex/Pragma.cpp +++ clang/lib/Lex/Pragma.cpp @@ -1023,8 +1023,10 @@ // Verify that this is followed by EOD. LexUnexpandedToken(Tok); - if (Tok.isNot(tok::eod)) + if (Tok.isNot(tok::eod)) { Diag(Tok, diag::ext_pragma_syntax_eod); + DiscardUntilEndOfDirective(); + } return false; } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -10176,6 +10176,11 @@ /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled); + /// ActOnPragmaComplexLimitedRange - Called on well formed + /// \#pragma STDC CX_LIMITED_RANGE + void ActOnPragmaComplexLimitedRange(SourceLocation Loc, + LangOptions::ComplexRangeKind Range); + /// Called on well formed '\#pragma clang fp' that has option 'exceptions'. void ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind); Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -749,6 +749,10 @@ /// #pragma STDC FENV_ROUND... void HandlePragmaFEnvRound(); + /// Handle the annotation token produced for + /// #pragma STDC CX_LIMITED_RANGE... + void HandlePragmaComplexLimitedRange(); + /// 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 @@ -841,6 +841,11 @@ // handles them. PRAGMA_ANNOTATION(pragma_fenv_round) +// Annotation for #pragma STDC CX_LIMITED_RANGE +// The lexer produces these so that they only take effect when the parser +// handles them. +PRAGMA_ANNOTATION(pragma_cx_limited_range) + // Annotation for #pragma float_control // The lexer produces these so that they only take effect when the parser // handles them.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits