Commit bd26f5ea authored by Mark Heffernan's avatar Mark Heffernan
Browse files

Add support for '#pragma unroll'.

llvm-svn: 213574
parent 4f42fc4e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -111,6 +111,13 @@ interleaving, and unrolling to be enabled or disabled. Vector width as well
as interleave and unrolling count can be manually specified.  See language
extensions for details.

Clang now supports the `#pragma unroll` directive to specify loop unrolling
optimization hints.  Placed just prior to the desired loop, `#pragma unroll`
directs the loop unroller to attempt to fully unroll the loop.  The pragma may
also be specified with a positive integer parameter indicating the desired
unroll count: `#pragma unroll _value_`.  The unroll count parameter can be
optionally enclosed in parentheses.

C Language Changes in Clang
---------------------------

+38 −6
Original line number Diff line number Diff line
@@ -1779,7 +1779,7 @@ def LoopHint : Attr {
  /// unroll: unroll loop if 'value != 0'.
  /// unroll_count: unrolls loop 'value' times.

  let Spellings = [Pragma<"clang", "loop">];
  let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];

  /// State of the loop optimization specified by the spelling.
  let Args = [EnumArgument<"Option", "OptionType",
@@ -1809,15 +1809,47 @@ def LoopHint : Attr {
  }

  void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
    OS << getOptionName(option) << "(";
    unsigned SpellingIndex = getSpellingListIndex();
    if (SpellingIndex == Pragma_unroll) {
      // String "unroll" of "#pragma unroll" is already emitted as the
      // pragma name.
      if (option == UnrollCount)
        OS << getValueString();
      OS << "\n";
      return;
    }
    assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
    OS << getOptionName(option) << getValueString() << "\n";
  }

  // Return a string containing the loop hint argument including the
  // enclosing parentheses.
  std::string getValueString() const {
    std::string ValueName;
    if (option == VectorizeWidth || option == InterleaveCount ||
        option == UnrollCount)
      OS << value;
      ValueName = std::to_string(value);
    else if (value)
      ValueName = "enable";
    else
      OS << getValueName(value);
    OS << ")\n";
      ValueName = "disable";

    return "(" + ValueName + ")";
  }

  // Return a string suitable for identifying this attribute in diagnostics.
  std::string getDiagnosticName() const {
    unsigned SpellingIndex = getSpellingListIndex();
    if (SpellingIndex == Pragma_unroll && option == Unroll)
      return "#pragma unroll";
    else if (SpellingIndex == Pragma_unroll && option == UnrollCount) {
      return "#pragma unroll" + getValueString();
    } else {
      assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
      return std::string(getOptionName(option)) + getValueString();
    }
  }
  }];

  let Documentation = [LoopHintDocs];
  let Documentation = [LoopHintDocs, UnrollHintDocs];
}
+42 −0
Original line number Diff line number Diff line
@@ -1045,3 +1045,45 @@ as interleave and unrolling count can be manually specified. See
for details.
  }];
}

def UnrollHintDocs : Documentation {
  let Category = DocCatStmt;
  let Content = [{
Loop unrolling optimization hints can be specified with ``#pragma unroll``. The
pragma is placed immediately before a for, while, do-while, or c++11 range-based
for loop.

Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
attempt to fully unroll the loop if the trip count is known at compile time:

.. code-block:: c++

  #pragma unroll
  for (...) {
    ...
  }

Specifying the optional parameter, ``#pragma unroll _value_``, directs the
unroller to unroll the loop ``_value_`` times.  The parameter may optionally be
enclosed in parentheses:

.. code-block:: c++

  #pragma unroll 16
  for (...) {
    ...
  }

  #pragma unroll(16)
  for (...) {
    ...
  }

``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
``#pragma clang loop unroll(enable)`` and ``#pragma clang loop
unroll_count(_value_)`` respectively. See `language extensions
<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
for further details including limitations of the unroll hints.
  }];
}
+4 −0
Original line number Diff line number Diff line
@@ -709,3 +709,7 @@ def BackendOptimizationFailure : DiagGroup<"pass-failed">;
// Instrumentation based profiling warnings.
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;

// A warning group for warnings about code that clang accepts when
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
def CudaCompat : DiagGroup<"cuda-compat">;
+8 −4
Original line number Diff line number Diff line
@@ -813,6 +813,9 @@ def warn_pragma_expected_punc : Warning<
  "expected ')' or ',' in '#pragma %0'">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_non_wide_string : Warning<
  "expected non-wide string literal in '#pragma %0'">, InGroup<IgnoredPragmas>;
// - Generic errors
def err_pragma_missing_argument : Error<
  "missing argument to '#pragma %0'; expected %1">;
// - #pragma options
def warn_pragma_options_expected_align : Warning<
  "expected 'align' following '#pragma options' - ignored">,
@@ -860,8 +863,6 @@ def err_pragma_pointers_to_members_unknown_kind : Error<
  "unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
  "'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'">;
// - #pragma clang optimize on/off
def err_pragma_optimize_missing_argument : Error<
  "missing argument to '#pragma clang optimize'; expected 'on' or 'off'">;
def err_pragma_optimize_invalid_argument : Error<
  "unexpected argument '%0' to '#pragma clang optimize'; "
  "expected 'on' or 'off'">;
@@ -917,8 +918,11 @@ def err_omp_expected_identifier_for_critical : Error<
def err_pragma_loop_invalid_option : Error<
  "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
  "vectorize_width, interleave, interleave_count, unroll, or unroll_count">;
def err_pragma_loop_missing_argument : Error<
  "missing argument to loop pragma %0">;

// Pragma unroll support.
def warn_pragma_unroll_cuda_value_in_parens : Warning<
  "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
  InGroup<CudaCompat>;
} // end of Parse Issue category.

let CategoryName = "Modules Issue" in {
Loading