r299470 - Add #pragma clang fp

Adam Nemet via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 4 14:18:36 PDT 2017


Author: anemet
Date: Tue Apr  4 16:18:36 2017
New Revision: 299470

URL: http://llvm.org/viewvc/llvm-project?rev=299470&view=rev
Log:
Add #pragma clang fp

This adds the new pragma and the first variant, contract(on/off/fast).

The pragma has the same block scope rules as STDC FP_CONTRACT, i.e. it can be
placed at the beginning of a compound statement or at file scope.

Similarly to STDC FP_CONTRACT there is no need to use attributes.  First an
annotate token is inserted with the parsed details of the pragma.  Then the
annotate token is parsed in the proper contexts and the Sema is updated with
the corresponding FPOptions using the shared ActOn function with STDC
FP_CONTRACT.

After this the FPOptions from the Sema is propagated into the AST expression
nodes.  There is no change here.

I was going to add a 'default' option besides 'on/off/fast' similar to STDC
FP_CONTRACT but then decided against it. I think that we'd have to make option
uppercase then to avoid using 'default' the keyword.  Also because of the
scoped activation of pragma I am not sure there is really a need a for this.

Differential Revision: https://reviews.llvm.org/D31276

Added:
    cfe/trunk/test/CodeGen/fp-contract-fast-pragma.cpp
    cfe/trunk/test/CodeGen/fp-contract-on-pragma.cpp
    cfe/trunk/test/Parser/pragma-fp.cpp
Modified:
    cfe/trunk/docs/LanguageExtensions.rst
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/TokenKinds.def
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParsePragma.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaAttr.cpp
    cfe/trunk/test/Parser/cxx11-stmt-attributes.cpp

Modified: cfe/trunk/docs/LanguageExtensions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.rst?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.rst (original)
+++ cfe/trunk/docs/LanguageExtensions.rst Tue Apr  4 16:18:36 2017
@@ -2312,3 +2312,36 @@ For example, the hint ``vectorize_width(
 proven safe to vectorize. To identify and diagnose optimization issues use
 `-Rpass`, `-Rpass-missed`, and `-Rpass-analysis` command line options. See the
 user guide for details.
+
+Extensions to specify floating-point flags
+====================================================
+
+The ``#pragma clang fp`` pragma allows floating-point options to be specified
+for a section of the source code. This pragma can only appear at file scope or
+at the start of a compound statement (excluding comments). When using within a
+compound statement, the pragma is active within the scope of the compound
+statement.
+
+Currently, only FP contraction can be controlled with the pragma. ``#pragma
+clang fp contract`` specifies whether the compiler should contract a multiply
+and an addition (or subtraction) into a fused FMA operation when supported by
+the target.
+
+The pragma can take three values: ``on``, ``fast`` and ``off``.  The ``on``
+option is identical to using ``#pragma STDC FP_CONTRACT(ON)`` and it allows
+fusion as specified the language standard.  The ``fast`` option allows fusiong
+in cases when the language standard does not make this possible (e.g. across
+statements in C)
+
+.. code-block:: c++
+
+  for(...) {
+    #pragma clang fp contract(fast)
+    a = b[i] * c[i];
+    d[i] += a;
+  }
+
+
+The pragma can also be used with 'off' which turns FP contraction off for a
+section of the code. This can be useful when fast contraction is otherwise
+enabled for the translation unit with the ``-ffp-contract=fast` flag.

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Apr  4 16:18:36 2017
@@ -1040,6 +1040,16 @@ def err_pragma_loop_missing_argument : E
 def err_pragma_loop_invalid_option : Error<
   "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
   "vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute">;
+
+def err_pragma_fp_invalid_option : Error<
+  "%select{invalid|missing}0 option%select{ %1|}0; expected contract">;
+def err_pragma_fp_invalid_argument : Error<
+  "unexpected argument '%0' to '#pragma clang fp %1'; "
+  "expected 'on', 'fast' or 'off'">;
+def err_pragma_fp_scope : Error<
+  "'#pragma clang fp' can only appear at file scope or at the start of a "
+  "compound statement">;
+
 def err_pragma_invalid_keyword : Error<
   "invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
 

Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Tue Apr  4 16:18:36 2017
@@ -787,6 +787,8 @@ ANNOTATION(pragma_openmp_end)
 // handles #pragma loop ... directives.
 ANNOTATION(pragma_loop_hint)
 
+ANNOTATION(pragma_fp)
+
 // Annotations for module import translated from #include etc.
 ANNOTATION(module_include)
 ANNOTATION(module_begin)

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Apr  4 16:18:36 2017
@@ -183,6 +183,7 @@ class Parser : public CodeCompletionHand
   std::unique_ptr<PragmaHandler> LoopHintHandler;
   std::unique_ptr<PragmaHandler> UnrollHintHandler;
   std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
+  std::unique_ptr<PragmaHandler> FPHandler;
 
   std::unique_ptr<CommentHandler> CommentSemaHandler;
 
@@ -549,6 +550,10 @@ private:
   void HandlePragmaFPContract();
 
   /// \brief Handle the annotation token produced for
+  /// #pragma clang fp ...
+  void HandlePragmaFP();
+
+  /// \brief Handle the annotation token produced for
   /// #pragma OPENCL EXTENSION...
   void HandlePragmaOpenCLExtension();
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Apr  4 16:18:36 2017
@@ -8120,8 +8120,9 @@ public:
                             SourceLocation AliasNameLoc);
 
   /// ActOnPragmaFPContract - Called on well formed
-  /// \#pragma {STDC,OPENCL} FP_CONTRACT
-  void ActOnPragmaFPContract(tok::OnOffSwitch OOS);
+  /// \#pragma {STDC,OPENCL} FP_CONTRACT and
+  /// \#pragma clang fp contract
+  void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC);
 
   /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
   /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'.

Modified: cfe/trunk/lib/Parse/ParsePragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParsePragma.cpp?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParsePragma.cpp (original)
+++ cfe/trunk/lib/Parse/ParsePragma.cpp Tue Apr  4 16:18:36 2017
@@ -86,6 +86,12 @@ struct PragmaFPContractHandler : public
                     Token &FirstToken) override;
 };
 
+struct PragmaFPHandler : public PragmaHandler {
+  PragmaFPHandler() : PragmaHandler("fp") {}
+  void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                    Token &FirstToken) override;
+};
+
 struct PragmaNoOpenMPHandler : public PragmaHandler {
   PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
   void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -266,6 +272,9 @@ void Parser::initializePragmaHandlers()
 
   NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
   PP.AddPragmaHandler(NoUnrollHintHandler.get());
+
+  FPHandler.reset(new PragmaFPHandler());
+  PP.AddPragmaHandler("clang", FPHandler.get());
 }
 
 void Parser::resetPragmaHandlers() {
@@ -344,6 +353,9 @@ void Parser::resetPragmaHandlers() {
 
   PP.RemovePragmaHandler(NoUnrollHintHandler.get());
   NoUnrollHintHandler.reset();
+
+  PP.RemovePragmaHandler("clang", FPHandler.get());
+  FPHandler.reset();
 }
 
 /// \brief Handle the annotation token produced for #pragma unused(...)
@@ -454,7 +466,21 @@ void Parser::HandlePragmaFPContract() {
   tok::OnOffSwitch OOS =
     static_cast<tok::OnOffSwitch>(
     reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
-  Actions.ActOnPragmaFPContract(OOS);
+
+  LangOptions::FPContractModeKind FPC;
+  switch (OOS) {
+  case tok::OOS_ON:
+    FPC = LangOptions::FPC_On;
+    break;
+  case tok::OOS_OFF:
+    FPC = LangOptions::FPC_Off;
+    break;
+  case tok::OOS_DEFAULT:
+    FPC = getLangOpts().getDefaultFPContractMode();
+    break;
+  }
+
+  Actions.ActOnPragmaFPContract(FPC);
   ConsumeToken(); // The annotation token.
 }
 
@@ -1947,6 +1973,129 @@ void PragmaOptimizeHandler::HandlePragma
   Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
 }
 
+namespace {
+/// Used as the annotation value for tok::annot_pragma_fp.
+struct TokFPAnnotValue {
+  enum FlagKinds { Contract };
+  enum FlagValues { On, Off, Fast };
+
+  FlagKinds FlagKind;
+  FlagValues FlagValue;
+};
+} // end anonymous namespace
+
+void PragmaFPHandler::HandlePragma(Preprocessor &PP,
+                                   PragmaIntroducerKind Introducer,
+                                   Token &Tok) {
+  // fp
+  Token PragmaName = Tok;
+  SmallVector<Token, 1> TokenList;
+
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::identifier)) {
+    PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+        << /*MissingOption=*/true << "";
+    return;
+  }
+
+  while (Tok.is(tok::identifier)) {
+    IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
+
+    auto FlagKind =
+        llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
+            OptionInfo->getName())
+            .Case("contract", TokFPAnnotValue::Contract)
+            .Default(None);
+    if (!FlagKind) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+          << /*MissingOption=*/false << OptionInfo;
+      return;
+    }
+    PP.Lex(Tok);
+
+    // Read '('
+    if (Tok.isNot(tok::l_paren)) {
+      PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+      return;
+    }
+    PP.Lex(Tok);
+
+    if (Tok.isNot(tok::identifier)) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+          << PP.getSpelling(Tok) << OptionInfo->getName();
+      return;
+    }
+    const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+    auto FlagValue =
+        llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
+            II->getName())
+            .Case("on", TokFPAnnotValue::On)
+            .Case("off", TokFPAnnotValue::Off)
+            .Case("fast", TokFPAnnotValue::Fast)
+            .Default(llvm::None);
+
+    if (!FlagValue) {
+      PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+          << PP.getSpelling(Tok) << OptionInfo->getName();
+      return;
+    }
+    PP.Lex(Tok);
+
+    // Read ')'
+    if (Tok.isNot(tok::r_paren)) {
+      PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+      return;
+    }
+    PP.Lex(Tok);
+
+    auto *AnnotValue = new (PP.getPreprocessorAllocator())
+        TokFPAnnotValue{*FlagKind, *FlagValue};
+    // Generate the loop hint token.
+    Token FPTok;
+    FPTok.startToken();
+    FPTok.setKind(tok::annot_pragma_fp);
+    FPTok.setLocation(PragmaName.getLocation());
+    FPTok.setAnnotationEndLoc(PragmaName.getLocation());
+    FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
+    TokenList.push_back(FPTok);
+  }
+
+  if (Tok.isNot(tok::eod)) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+        << "clang fp";
+    return;
+  }
+
+  auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+  std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
+
+  PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
+                      /*DisableMacroExpansion=*/false);
+}
+
+void Parser::HandlePragmaFP() {
+  assert(Tok.is(tok::annot_pragma_fp));
+  auto *AnnotValue =
+      reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
+
+  LangOptions::FPContractModeKind FPC;
+  switch (AnnotValue->FlagValue) {
+  case TokFPAnnotValue::On:
+    FPC = LangOptions::FPC_On;
+    break;
+  case TokFPAnnotValue::Fast:
+    FPC = LangOptions::FPC_Fast;
+    break;
+  case TokFPAnnotValue::Off:
+    FPC = LangOptions::FPC_Off;
+    break;
+  }
+
+  Actions.ActOnPragmaFPContract(FPC);
+  ConsumeToken(); // The annotation token.
+}
+
 /// \brief Parses loop or unroll pragma hint value and fills in Info.
 static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
                                Token Option, bool ValueInParens,

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Tue Apr  4 16:18:36 2017
@@ -341,6 +341,12 @@ Retry:
     ConsumeToken();
     return StmtError();
 
+  case tok::annot_pragma_fp:
+    ProhibitAttributes(Attrs);
+    Diag(Tok, diag::err_pragma_fp_scope);
+    ConsumeToken();
+    return StmtError();
+
   case tok::annot_pragma_opencl_extension:
     ProhibitAttributes(Attrs);
     HandlePragmaOpenCLExtension();
@@ -900,6 +906,9 @@ void Parser::ParseCompoundStatementLeadi
     case tok::annot_pragma_fp_contract:
       HandlePragmaFPContract();
       break;
+    case tok::annot_pragma_fp:
+      HandlePragmaFP();
+      break;
     case tok::annot_pragma_ms_pointers_to_members:
       HandlePragmaMSPointersToMembers();
       break;

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Apr  4 16:18:36 2017
@@ -670,6 +670,9 @@ Parser::ParseExternalDeclaration(ParsedA
   case tok::annot_pragma_fp_contract:
     HandlePragmaFPContract();
     return nullptr;
+  case tok::annot_pragma_fp:
+    HandlePragmaFP();
+    break;
   case tok::annot_pragma_opencl_extension:
     HandlePragmaOpenCLExtension();
     return nullptr;

Modified: cfe/trunk/lib/Sema/SemaAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAttr.cpp?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAttr.cpp Tue Apr  4 16:18:36 2017
@@ -448,19 +448,16 @@ void Sema::ActOnPragmaVisibility(const I
   }
 }
 
-void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) {
-  switch (OOS) {
-  case tok::OOS_ON:
+void Sema::ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC) {
+  switch (FPC) {
+  case LangOptions::FPC_On:
     FPFeatures.setAllowFPContractWithinStatement();
     break;
-  case tok::OOS_OFF:
-    FPFeatures.setDisallowFPContract();
+  case LangOptions::FPC_Fast:
+    FPFeatures.setAllowFPContractAcrossStatement();
     break;
-  case tok::OOS_DEFAULT:
-    if (getLangOpts().getDefaultFPContractMode() == LangOptions::FPC_On)
-      FPFeatures.setAllowFPContractWithinStatement();
-    else
-      FPFeatures.setDisallowFPContract();
+  case LangOptions::FPC_Off:
+    FPFeatures.setDisallowFPContract();
     break;
   }
 }

Added: cfe/trunk/test/CodeGen/fp-contract-fast-pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/fp-contract-fast-pragma.cpp?rev=299470&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/fp-contract-fast-pragma.cpp (added)
+++ cfe/trunk/test/CodeGen/fp-contract-fast-pragma.cpp Tue Apr  4 16:18:36 2017
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+// Is FP_CONTRACT honored in a simple case?
+float fp_contract_1(float a, float b, float c) {
+// CHECK: _Z13fp_contract_1fff
+// CHECK: %[[M:.+]] = fmul contract float %a, %b
+// CHECK-NEXT: fadd contract float %[[M]], %c
+#pragma clang fp contract(fast)
+  return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_2fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  {
+#pragma clang fp contract(fast)
+  }
+  return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instantiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+#pragma clang fp contract(fast)
+  return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_3fff
+  // CHECK: %[[M:.+]] = fmul contract float %a, %b
+  // CHECK-NEXT: fadd contract float %[[M]], %c
+  return template_muladd<float>(a, b, c);
+}
+
+template <typename T>
+class fp_contract_4 {
+  float method(float a, float b, float c) {
+#pragma clang fp contract(fast)
+    return a * b + c;
+  }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: %[[M:.+]] = fmul contract float %a, %b
+// CHECK-NEXT: fadd contract float %[[M]], %c
+
+// Check file-scoped FP_CONTRACT
+#pragma clang fp contract(fast)
+float fp_contract_5(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_5fff
+  // CHECK: %[[M:.+]] = fmul contract float %a, %b
+  // CHECK-NEXT: fadd contract float %[[M]], %c
+  return a * b + c;
+}
+
+// Verify that we can handle multiple flags on the same pragma
+#pragma clang fp contract(fast) contract(off)
+float fp_contract_6(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_6fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  return a * b + c;
+}

Added: cfe/trunk/test/CodeGen/fp-contract-on-pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/fp-contract-on-pragma.cpp?rev=299470&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/fp-contract-on-pragma.cpp (added)
+++ cfe/trunk/test/CodeGen/fp-contract-on-pragma.cpp Tue Apr  4 16:18:36 2017
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -O3 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s
+
+// Is FP_CONTRACT honored in a simple case?
+float fp_contract_1(float a, float b, float c) {
+// CHECK: _Z13fp_contract_1fff
+// CHECK: tail call float @llvm.fmuladd
+#pragma clang fp contract(on)
+  return a * b + c;
+}
+
+// Is FP_CONTRACT state cleared on exiting compound statements?
+float fp_contract_2(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_2fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  {
+#pragma clang fp contract(on)
+  }
+  return a * b + c;
+}
+
+// Does FP_CONTRACT survive template instantiation?
+class Foo {};
+Foo operator+(Foo, Foo);
+
+template <typename T>
+T template_muladd(T a, T b, T c) {
+#pragma clang fp contract(on)
+  return a * b + c;
+}
+
+float fp_contract_3(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_3fff
+  // CHECK: tail call float @llvm.fmuladd
+  return template_muladd<float>(a, b, c);
+}
+
+template <typename T>
+class fp_contract_4 {
+  float method(float a, float b, float c) {
+#pragma clang fp contract(on)
+    return a * b + c;
+  }
+};
+
+template class fp_contract_4<int>;
+// CHECK: _ZN13fp_contract_4IiE6methodEfff
+// CHECK: tail call float @llvm.fmuladd
+
+// Check file-scoped FP_CONTRACT
+#pragma clang fp contract(on)
+float fp_contract_5(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_5fff
+  // CHECK: tail call float @llvm.fmuladd
+  return a * b + c;
+}
+
+#pragma clang fp contract(off)
+float fp_contract_6(float a, float b, float c) {
+  // CHECK: _Z13fp_contract_6fff
+  // CHECK: %[[M:.+]] = fmul float %a, %b
+  // CHECK-NEXT: fadd float %[[M]], %c
+  return a * b + c;
+}
+
+// If the multiply has multiple uses, don't produce fmuladd.
+// This used to assert (PR25719):
+// https://llvm.org/bugs/show_bug.cgi?id=25719
+
+float fp_contract_7(float a, float b, float c) {
+// CHECK: _Z13fp_contract_7fff
+// CHECK:  %[[M:.+]] = fmul float %b, 2.000000e+00
+// CHECK-NEXT: fsub float %[[M]], %c
+#pragma clang fp contract(on)
+  return (a = 2 * b) - c;
+}

Modified: cfe/trunk/test/Parser/cxx11-stmt-attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx11-stmt-attributes.cpp?rev=299470&r1=299469&r2=299470&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx11-stmt-attributes.cpp (original)
+++ cfe/trunk/test/Parser/cxx11-stmt-attributes.cpp Tue Apr  4 16:18:36 2017
@@ -80,5 +80,6 @@ void foo(int i) {
   {
     [[ ]] // expected-error {{an attribute list cannot appear here}}
 #pragma STDC FP_CONTRACT ON // expected-error {{can only appear at file scope or at the start of a compound statement}}
+#pragma clang fp contract(fast) // expected-error {{can only appear at file scope or at the start of a compound statement}}
   }
 }

Added: cfe/trunk/test/Parser/pragma-fp.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-fp.cpp?rev=299470&view=auto
==============================================================================
--- cfe/trunk/test/Parser/pragma-fp.cpp (added)
+++ cfe/trunk/test/Parser/pragma-fp.cpp Tue Apr  4 16:18:36 2017
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+void test_0(int *List, int Length) {
+/* expected-error at +1 {{missing option; expected contract}} */
+#pragma clang fp
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+void test_1(int *List, int Length) {
+/* expected-error at +1 {{invalid option 'blah'; expected contract}} */
+#pragma clang fp blah
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_3(int *List, int Length) {
+/* expected-error at +1 {{expected '('}} */
+#pragma clang fp contract on
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_4(int *List, int Length) {
+/* expected-error at +1 {{unexpected argument 'while' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+#pragma clang fp contract(while)
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_5(int *List, int Length) {
+/* expected-error at +1 {{unexpected argument 'maybe' to '#pragma clang fp contract'; expected 'on', 'fast' or 'off'}} */
+#pragma clang fp contract(maybe)
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_6(int *List, int Length) {
+/* expected-error at +1 {{expected ')'}} */
+#pragma clang fp contract(fast
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_7(int *List, int Length) {
+/* expected-warning at +1 {{extra tokens at end of '#pragma clang fp' - ignored}} */
+#pragma clang fp contract(fast) *
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+  }
+}
+
+void test_8(int *List, int Length) {
+  for (int i = 0; i < Length; i++) {
+    List[i] = i;
+/* expected-error at +1 {{'#pragma clang fp' can only appear at file scope or at the start of a compound statement}} */
+#pragma clang fp contract(fast)
+  }
+}




More information about the cfe-commits mailing list