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
  • [PATCH] D119291: [Clang] Ad... Joshua Cranmer via Phabricator via cfe-commits

Reply via email to