This is an archive of the discontinued LLVM Phabricator instance.

Add support for unroll pragma
Needs ReviewPublic

Authored by meheff on Jun 25 2014, 1:28 PM.

Details

Summary

This patch adds support for loop unroll pragma syntax:

// Fully unroll loop.
#pragma unroll
for (...) { }

// Unroll loop N times.
#pragma unroll N
for (...) { }

// Unroll loop N times (same effect as without the parentheses around N).
#pragma unroll(N)
for (...) { }

These pragmas replace the "#pragma clang loop unroll" and "#pragma clang loop unroll_count" directives.

Mark

Diff Detail

Event Timeline

meheff updated this revision to Diff 10856.Jun 25 2014, 1:28 PM
meheff retitled this revision from to Add support for CUDA unroll pragma.
meheff updated this object.
meheff edited the test plan for this revision. (Show Details)
meheff added a subscriber: Unknown Object (MLST).
eliben added a reviewer: pcc.Jun 25 2014, 1:47 PM
eliben added inline comments.Jun 25 2014, 3:19 PM
include/clang/Parse/Parser.h
1614

How about a comment above the method declaration that explains what those arguments are? I know the surrounding code doesn't do this, but with new code we can do better :)

include/clang/Sema/CudaUnrollHint.h
19 ↗(On Diff #10856)

Ditto... Documentation of every field in this struct.

lib/CodeGen/CGStmt.cpp
554 ↗(On Diff #10856)

Since MDNode::get accepts a ArrayRef, I wonder if there's a way to not have the OpValues vector at all?

At the minimum:

llvm::Value *Values[] = {MetadataPair.first, MetadataPair.second};
... MDNode::get(Context, Values);

It may be possible to inline the {...} into the ::get too, I haven't checked.

lib/Sema/SemaStmtAttr.cpp
133

You could fold this into the if (...)

meheff updated this revision to Diff 10862.Jun 25 2014, 4:31 PM

Thanks for the comments, Eli. This patch addresses them all.

include/clang/Parse/Parser.h
1614

Done.

include/clang/Sema/CudaUnrollHint.h
19 ↗(On Diff #10856)

Done.

lib/CodeGen/CGStmt.cpp
554 ↗(On Diff #10856)

Done.

lib/Sema/SemaStmtAttr.cpp
133

Done.

hfinkel added inline comments.
lib/Parse/ParsePragma.cpp
677

If this gets committed, please also add a corresponding note in the bug report that there is another instance of the issue to fix :)

meheff updated this revision to Diff 11012.Jul 1 2014, 3:59 PM
meheff retitled this revision from Add support for CUDA unroll pragma to Add support for unroll pragma.
meheff updated this object.

Thanks all for your comments. This patch reduces much of the implementation duplication from the previous patch. Unroll and loop optimization hints now both share the same attribute.

Also, the loop unroll pragma now replaces the "#pragma clang loop unroll/unroll_count" directives which have been removed. The following unroll pragma forms are supported:

#pragma unroll
#pragma unroll N
#pragma unroll(N)

The parentheses around the unroll count argument are optional. The form with parentheses is included to maximize compatibility with existing compilers (Intel and IBM compiler use the form with parentheses, CUDA uses the form without).

meheff updated this revision to Diff 11185.Jul 8 2014, 11:14 PM

Thanks for the comments. Responses are below. With this patch "#pragma unroll" and "#pragma clang loop unroll" syntaxes are both supported. I also added "#pragma nounroll" as both icc and xlc support this pragma.

On Wed, Jul 2, 2014 at 7:54 AM, Aaron Ballman <aaron.ballman@gmail.com> wrote:

/// State of the loop optimization specified by the spelling.
let Args = [EnumArgument<"Option", "OptionType",
                        ["vectorize", "vectorize_width", "interleave", "interleave_count",
                         "unroll", "unroll_count"],
                        ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
                         "Unroll", "UnrollCount"]>,
  • DefaultIntArgument<"Value", 1>];

+ DefaultIntArgument<"Value", 1>,
+ DefaultBoolArgument<"ValueInParens", 0>];

Hmm... we usually want the arguments to match the syntax of the
attribute unless the argument is really key to the semantics.
ValueInParens doesn't really fit that model. I would prefer for this
to be an AdditionalMembers entry.

I tried putting ValueInParens in the AdditionalMembers, but then ran into issues with test/PCH/pragma-loop. I just added a member variable and a method to set it, but then ValueInParens is then not set when reading in the PCH file. It only works if ValueInParens is not in Args. Am I missing something?

"%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">;

+ "missing argument to %0 pragma">;

The name of this diagnostic should probably change given how generic
the text now is.

Done.

+def err_pragma_loop_duplicate : Error<
+ "duplicate '%0' directives">;
+def err_pragma_loop_incompatible : Error<
+ "incompatible directives '%0(%1)' and '%2(%3)'">;

Why was this split into two errors?

This was originally done because the duplicate form was also used when there was no parameter such as '#pragma unroll'. I've refactored it and now they are back to being one error.

+// Parses loop or unroll pragma hint value and fills in Info.

+bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
+ Token &Option, PragmaLoopHintInfo &Info) {
+ bool ValueInParens;

Could simply initialize to Tok.is(tok::l_paren), then not need the
else clause at all.

Good point. Done.

-static void
-CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
+static void CheckForIncompatibleAttributes(
+ Sema &S, SmallVectorImpl<const Attr *> &Attrs) {

Attrs should be const.

Done.

meheff updated this revision to Diff 11466.Jul 15 2014, 2:09 PM

I added a warning if the wrong pragma unroll syntax is used with CUDA. When Tyler's change adding support for expressions in loop pragmas lands, I'll add a warning for the case when the pragma argument is not an integer literal in CUDA mode. Responses to Aaron's comments inline.

On Wed, Jul 9, 2014 at 7:42 AM, Aaron Ballman <aaron.ballman@gmail.com> wrote:

On Wed, Jul 9, 2014 at 2:14 AM, Mark Heffernan <meheff@google.com> wrote:

I also added "#pragma nounroll" as both icc and xlc support this pragma.

Please split nounroll out into a separate patch. The idea is certainly
reasonable, but it's preferable for patches to cover a limited,
incremental change.

Done.

On Wed, Jul 2, 2014 at 7:54 AM, Aaron Ballman <aaron.ballman@gmail.com> wrote:

Okay, I can see why that would happen. ClangAtterEmitter.cpp generates
code for serialization and deserialization, but it doesn't have any
way of handling additional members (since those are just copy/pasted
into the attribute class definition itself).

I wonder how horrible it would be to simply canonicalize based on
compiler options when pretty printing, and skip this field entirely.
Eg) when CUDA is on, pretty print does not emit the parens. When CUDA
mode is off, it does emit the parens. Yes, this isn't *exactly* what
the user wrote, but the semantics are identical either way.

It's now cannonicalized to the form with parentheses '#pragma unroll(n)'.  Tracking of the existence of parentheses is gone.

Index: include/clang/Basic/DiagnosticParseKinds.td

  • include/clang/Basic/DiagnosticParseKinds.td

+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -811,6 +811,9 @@
   InGroup<IgnoredPragmas>;
 def warn_pragma_expected_punc : Warning<
   "expected ')' or ',' in '#pragma %0'">, InGroup<IgnoredPragmas>;
+// - Generic errors
+def err_pragma_missing_argument : Error<
+  "missing argument to %0 directive">;

Since it's a generic parsing diagnostic, presumably we know what kind
of argument is missing, and we could tell the user that information.
What's more, since pragmas can have multiple arguments, this doesn't
say *which* argument is missing (there could be more than one).

I also think the word "directive" could be dropped.

Created a generic diagnostic: "missing argument to '#pragma %0'; expected %1".  This new warning is also now shared with one pragma optimize warning.  Regarding stating which argument is missing, all of the pragmas using this warning only take a single argument.  I think it makes sense not to specify argument position unless multiple arguments are allowed.  That is, "missing first argument to '#pragma unroll'" suggests pragma unroll accepts more than one argument.  If this error is later used for pragmas with multiple parameters, the format string can be adjusted accordingly.

 def err_pragma_loop_precedes_nonloop : Error<

  •  "expected a for, while, or do-while loop to follow the '#pragma clang loop' "
  •  "directive">;

+  "expected a for, while, or do-while loop to follow the '%0' directive">;

I would drop "directive" (and "the") here too.

Done.

aaron.ballman resigned from this revision.Oct 13 2015, 5:49 AM
aaron.ballman removed a reviewer: aaron.ballman.