[PATCH] #pragma vectorize

Aaron Ballman aaron at aaronballman.com
Tue May 13 08:22:25 PDT 2014


After committing r208702/3, your tests now pass for me. I'll take it
on faith that the comment and formatting gets resolved when you
commit, so LGTM. You should wait for Richard to sign off as well,
since he had some comments.

~Aaron

On Tue, May 13, 2014 at 10:07 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
> So I did a bit of looking at the crash issue, and this isn't Tyler's
> bug. It's a bug with the way AttributedStmt is written. It has a
> member declaration:
>
>   const Attr *Attrs[1];
>
> So when std::copy is called with MSVC, a checked iterator overload is
> called which says that there's only one element in the destination
> array. So when we attempt to copy two attributes into the array, we
> get the debug assert.
>
> At first blush, ASTStmtReader::VisitAttributedStmt looks to be wrong.
> It never allocates space for the attributes that it copies in, so
> anything other than the first attribute will be a memory stomp.
>
> I'll take a stab at fixing this.
>
> ~Aaron
>
> On Tue, May 13, 2014 at 9:56 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
>> On Mon, May 12, 2014 at 7:20 PM, Tyler Nowicki <tnowicki at apple.com> wrote:
>>> Hi Aaron, Ben,
>>>
>>> Thank again for the review. I’ve made the changes you suggested.
>>>
>>> There was a question about why I reversed the iteration over the attribute
>>> list. The answer is that the attribute list built by ParsedAttributes stores
>>> attributes in reverse order. However, this is wrong because the correct
>>> order should be maintained for serialization/deserialization and error
>>> reporting. So we have to iterate rbegin->rend. Ideally the ParsedAttributes
>>> list should be fixed to store attributes in the order they appear but this
>>> looks like a lot of work.
>>
>> Ah, yes. That problem keeps rearing its ugly head. :-/
>>
>>>
>>> Tyler
>>>
>>>
>>>
>>>
>>> That part of tablegen probably shouldn’t be specialized for each type of
>>> pragma should it? But from your comment below it sounds like thats what you
>>> are thinking.
>>>
>>>
>>> I'd have to think about it more, but it seems like tablegen shouldn't
>>> have to specialize for each pragma, just all pragmas. Eg) the
>>> difference between printing pragmas and printing attributes is minor
>>> enough that it could be handled entirely by tablegen without the
>>> pragma authors having to write special code.
>>>
>>>
>>> I’m pretty sure that each type of pragma has a unique syntax that makes it
>>> difficult to generalize.
>>>
>>>
>>> +                          ["disable", "enable", "value"],
>>> +                          ["Disable", "Enable", "Value"]>,
>>>
>>>
>>> This is actually an optional argument as well, but is not marked as
>>> such. It should get a , 1. Also, this suggests we need a new argument
>>> type that represents a union of arguments, since that's really what
>>> you want (one of these two arguments must be used, but you don't care
>>> which). A FIXME would probably be appropriate (though you don't have
>>> to implement the functionality for this patch).
>>>
>>>
>>> I don’t think it is. Just specifying vectorize or interleave does not imply
>>> a default action. Perhaps it should?
>>
>> As it's written, it implies that you must specify vectorize or
>> interleave, followed by disable/enable/value, and then optionally
>> supply a value. Eg) #pragma loop vectorize(enable, 4)
>>
>> That's why I think we should have a Union argument type because you
>> really want it to either be enable|disable, or an integer value, not
>> both.
>>
>> Not something that needs doing for this patch by any means. :-)
>>
>>>
>>>
>>> +              ExprArgument<"Value", 1>];
>>>
>>>
>>> Judging by the tests, this should be a DefaultIntArgument<"Value", 1>.
>>> Either that, or there are tests missing where expressions are used
>>> (and honestly, it would strike me as slightly strange to allow general
>>> expressions here).
>>>
>>>
>>> I was thinking ahead to non-type template arguments. But that can wait. I’ll
>>> use an int for now.
>>>
>>>
>>> const char *Names[] = { "llvm.vectorizer.width", "llvm.vectorizer.unroll" };
>>> llvm::Value *Value;
>>> llvm::MDString *Name;
>>>
>>> if (Kind == LoopHintAttr::Enable) {
>>>  Name = llvm::MDString::get(Context, "llvm.vectorizer.enable");
>>>  Value = Builder.getTrue();
>>> } else {
>>>  Name = llvm::MDString::get(Context, Names[Option]);
>>>  Value = llvm::ConstantInt::get(Int32Ty, ValueInt); // You already
>>> set ValueInt to 1 by default, and overwrite when the Kind is a Value.
>>> }
>>>
>>>
>>> Good idea!
>>>
>>>
>>> +  }
>>> +
>>> +  // Get the next statement.
>>> +  MaybeParseCXX11Attributes(Attrs);
>>> +
>>> +  StmtResult S = ParseStatementOrDeclarationAfterAttributes(Stmts,
>>> +                  /*OnlyStatement*/ true, 0, Attrs);
>>>
>>>
>>> Shouldn't we be passing the OnlyStatement which was passed into the
>>> function? Same for passing in the TrailingElseLoc instead of 0?
>>>
>>>
>>> These inputs confused me, I duplicated the call made in
>>> ParseLabeledStatement(). I think OnlyStatement indicates that the next thing
>>> parsed is expected be a statement, rather than a declaration. I’ll pass the
>>> arguments as you suggest.
>>>
>>>
>>> Btw, when I test your patch locally, I get failed assertions from the
>>> STL. "array iterator + offset out of range" on a call to std::copy
>>> within ASTStmtReader::VisitAttributedStmt().
>>>
>>>
>>> I don’t seem to have that, also I didn’t make any changes to ASTStmtReader?
>>> Could you try out the attached patch and provide the stack dump if it fails
>>> again.
>>
>> Yup, still failing.
>>
>> 58>  FAIL: Clang :: PCH/pragma-loop.cpp (3877 of 7229)
>> 58>  ******************** TEST 'Clang :: PCH/pragma-loop.cpp' FAILED
>> ********************
>> 58>  Script:
>> 58>  --
>> 58>  E:/llvm/2013/Debug/bin/clang.EXE -cc1 -internal-isystem
>> E:\llvm\2013\Debug\bin\..\lib\clang\3.5.0\include -emit-pch -o
>> E:\llvm\2013\tools\clang\test\PCH\Output\pragma-loop.cpp.tmp.a
>> E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp
>> 58>  E:/llvm/2013/Debug/bin/clang.EXE -cc1 -internal-isystem
>> E:\llvm\2013\Debug\bin\..\lib\clang\3.5.0\include -include-pch
>> E:\llvm\2013\tools\clang\test\PCH\Output\pragma-loop.cpp.tmp.a
>> E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp -ast-print -o - |
>> E:/llvm/2013/Debug/bin\FileCheck.EXE
>> E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp
>> 58>  --
>> 58>  Exit Code: 2
>> 58>
>> 58>  Command Output (stdout):
>> 58>  --
>> 58>  Command 0: "E:/llvm/2013/Debug/bin/clang.EXE" "-cc1"
>> "-internal-isystem"
>> "E:\llvm\2013\Debug\bin\..\lib\clang\3.5.0\include" "-emit-pch" "-o"
>> "E:\llvm\2013\tools\clang\test\PCH\Output\pragma-loop.cpp.tmp.a"
>> "E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp"
>> 58>  Command 0 Result: 0
>> 58>  Command 0 Output:
>> 58>
>> 58>
>> 58>  Command 0 Stderr:
>> 58>
>> 58>
>> 58>  Command 1: "E:/llvm/2013/Debug/bin/clang.EXE" "-cc1"
>> "-internal-isystem"
>> "E:\llvm\2013\Debug\bin\..\lib\clang\3.5.0\include" "-include-pch"
>> "E:\llvm\2013\tools\clang\test\PCH\Output\pragma-loop.cpp.tmp.a"
>> "E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp" "-ast-print" "-o"
>> "-"
>> 58>  Command 1 Result: -2147483645
>> 58>  Command 1 Output:
>> 58>
>> 58>
>> 58>  Command 1 Stderr:
>> 58>  Stack dump:
>> 58>
>> 58>  0. Program arguments: E:/llvm/2013/Debug/bin/clang.EXE -cc1
>> -internal-isystem E:\llvm\2013\Debug\bin\..\lib\clang\3.5.0\include
>> -include-pch E:\llvm\2013\tools\clang\test\PCH\Output\pragma-loop.cpp.tmp.a
>> E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp -ast-print -o -
>> 58>
>> 58>  1. <eof> parser at end of file
>> 58>
>> 58>  0x6C47CEE6 (0x055612B0 0x04BD89E0 0x00000618 0x00C6D504),
>> ?_Debug_message at std@@YAXPB_W0I at Z() + 0x26 bytes(s)
>> 58>
>> 58>  0x032A6E98 (0x00000002 0x00C6D434 0x00C6D44C 0x032A6E0B),
>> std::_Array_const_iterator<clang::Attr const *,1>::operator+=() + 0x38
>> bytes(s), d:\program files (x86)\microsoft visual studio
>> 12.0\vc\include\xutility, line 1560 + 0x17 byte(s)
>> 58>
>> 58>  0x032A6F4A (0x00000002 0xCCCCCCCC 0x00000000 0x00000000),
>> std::_Array_iterator<clang::Attr const *,1>::operator+=() + 0x1A
>> bytes(s), d:\program files (x86)\microsoft visual studio
>> 12.0\vc\include\xutility, line 1764
>> 58>
>> 58>  0x032A6E0B (0x00C6D464 0x00000002 0xCCCCCCCC 0xCCCCCCCC),
>> std::_Array_iterator<clang::Attr const *,1>::operator+() + 0x3B
>> bytes(s), d:\program files (x86)\microsoft visual studio
>> 12.0\vc\include\xutility, line 1770 + 0xC byte(s)
>> 58>
>> 58>  0x032A22D6 (0x00C6D504 0x00C6D564 0x00C6D56C 0x00000000),
>> std::_Copy_impl<clang::Attr * *,std::_Array_iterator<clang::Attr const
>> *,1> >() + 0x36 bytes(s), d:\program files (x86)\microsoft visual
>> studio 12.0\vc\include\xutility, line 2097
>> 58>
>> 58>  0x032A227F (0x00C6D504 0x00C6D564 0x00C6D56C 0x00000000),
>> std::_Copy_impl<clang::Attr * *,std::_Array_iterator<clang::Attr const
>> *,1> >() + 0x5F bytes(s), d:\program files (x86)\microsoft visual
>> studio 12.0\vc\include\xutility, line 2107 + 0x4B byte(s)
>> 58>
>> 58>  0x032A3313 (0x00C6D504 0x00C6D564 0x00C6D56C 0x00000000),
>> std::copy<clang::Attr * *,std::_Array_iterator<clang::Attr const *,1>
>>>() + 0xC3 bytes(s), d:\program files (x86)\microsoft visual studio
>> 12.0\vc\include\xutility, line 2132 + 0x4F byte(s)
>> 58>
>> 58>  0x032A3228 (0x00C6D564 0x00C6D56C 0x00FF510C 0x00C6DEFC),
>> std::copy<clang::Attr * *,clang::Attr const *,1>() + 0x38 bytes(s),
>> d:\program files (x86)\microsoft visual studio
>> 12.0\vc\include\xutility, line 2145 + 0x23 byte(s)
>> 58>
>> 58>  0x03297A73 (0x00FF50FC 0xCCCCCCCC 0x00000002 0xCCCCCCCC),
>> clang::ASTStmtReader::VisitAttributedStmt() + 0x133 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\serialization\astreaderstmt.cpp, line 179
>> + 0x1E byte(s)
>> 58>
>> 58>  0x032A7C3B (0x00FF50FC 0x00C6E3E4 0x00C6DF34 0xCCCCCCCC),
>> clang::StmtVisitorBase<clang::make_ptr,clang::ASTStmtReader,void>::Visit()
>> + 0x3FB bytes(s),
>> e:\llvm\llvm\tools\clang\include\clang\ast\stmtvisitor.h, line 43 +
>> 0xC byte(s)
>> 58>
>> 58>  0x03296804 (0x00FD6E30 0xCCCCCCCC 0x00FD6E30 0xCCCCCCCC),
>> clang::ASTReader::ReadStmtFromStream() + 0x3604 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\serialization\astreaderstmt.cpp, line
>> 2539
>> 58>
>> 58>  0x031CBE4A (0x00014648 0x00000000 0x00C6DF78 0x03BB3352),
>> clang::ASTReader::GetExternalDeclStmt() + 0x6A bytes(s),
>> e:\llvm\llvm\tools\clang\lib\serialization\astreader.cpp, line 6156
>> 58>
>> 58>  0x03BB42D8 (0x00FD40C4 0x00FD38C8 0x00C6DF70 0x03BB4416),
>> clang::LazyOffsetPtr<clang::Stmt,unsigned
>> __int64,{clang::ExternalASTSource::`vcall'{16}',0}>::get() + 0x88
>> bytes(s), e:\llvm\llvm\tools\clang\include\clang\ast\externalastsource.h,
>> line 351 + 0x2A byte(s)
>> 58>
>> 58>  0x03BA74F6 (0x00C6DF64 0xCCCCCCCC 0x00FD38C8 0xCCCCCCCC),
>> clang::FunctionDecl::getBody() + 0x56 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\ast\decl.cpp, line 2246 + 0x1D byte(s)
>> 58>
>> 58>  0x03BB4416 (0x00FC8880 0x00000000 0x00C6E304 0x00000002),
>> clang::FunctionDecl::getBody() + 0x26 bytes(s),
>> e:\llvm\llvm\tools\clang\include\clang\ast\decl.h, line 1654
>> 58>
>> 58>  0x03C4F282 (0x00FD38C8 0x00C6E5B0 0x00C6E408 0x03C524AC),
>> `anonymous namespace'::DeclPrinter::VisitFunctionDecl() + 0xD92
>> bytes(s), e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 589 +
>> 0x28 byte(s)
>> 58>
>> 58>  0x03C527DA (0x00FD38C8 0x0000002A 0x00C6E5B0 0x00C6E488),
>> clang::declvisitor::Base<clang::declvisitor::make_ptr,`anonymous
>> namespace'::DeclPrinter,void>::VisitCXXMethodDecl() + 0x1A bytes(s),
>> e:\llvm\2013\tools\clang\include\clang\ast\declnodes.inc, line 349 +
>> 0x1A byte(s)
>> 58>
>> 58>  0x03C524AC (0x00FD38C8 0x00C6E4DC 0x00C6E6EC 0xCCCCCCCC),
>> clang::declvisitor::Base<clang::declvisitor::make_ptr,`anonymous
>> namespace'::DeclPrinter,void>::Visit() + 0x30C bytes(s),
>> e:\llvm\llvm\tools\clang\include\clang\ast\declvisitor.h, line 349 +
>> 0xC byte(s)
>> 58>
>> 58>  0x03C4DD12 (0x00FD3548 0x00000001 0x00C6E570 0x00FD3548),
>> `anonymous namespace'::DeclPrinter::VisitDeclContext() + 0x2D2
>> bytes(s), e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 285
>> 58>
>> 58>  0x03C4FF83 (0x00FD3528 0x0000001C 0x00C6E5B0 0x00C6E570),
>> `anonymous namespace'::DeclPrinter::VisitCXXRecordDecl() + 0x1E3
>> bytes(s), e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 787
>> 58>
>> 58>  0x03C523BE (0x00FD3528 0x00C6E694 0x00C6E6EC 0xCCCCCCCC),
>> clang::declvisitor::Base<clang::declvisitor::make_ptr,`anonymous
>> namespace'::DeclPrinter,void>::Visit() + 0x21E bytes(s),
>> e:\llvm\llvm\tools\clang\include\clang\ast\declvisitor.h, line 233 +
>> 0xC byte(s)
>> 58>
>> 58>  0x03C4DD12 (0x00FD30D4 0x00000000 0x00FD30D4 0x00C6E5B0),
>> `anonymous namespace'::DeclPrinter::VisitDeclContext() + 0x2D2
>> bytes(s), e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 285
>> 58>
>> 58>  0x03C4E03D (0x00FD30C0 0x0000003B 0x00C6E5B0 0x00C6E694),
>> `anonymous namespace'::DeclPrinter::VisitTranslationUnitDecl() + 0x3D
>> bytes(s), e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 322
>> 58>
>> 58>  0x03C525B8 (0x00FD30C0 0x00C6E770 0xCCCCCCCC 0x00FC8880),
>> clang::declvisitor::Base<clang::declvisitor::make_ptr,`anonymous
>> namespace'::DeclPrinter,void>::Visit() + 0x418 bytes(s),
>> e:\llvm\llvm\tools\clang\include\clang\ast\declvisitor.h, line 473 +
>> 0xC byte(s)
>> 58>
>> 58>  0x03C4D5F6 (0x00FC8880 0x00FCF114 0x00000000 0x00000001),
>> clang::Decl::print() + 0x56 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 102
>> 58>
>> 58>  0x03C4D583 (0x00FC8880 0x00000000 0x00000001 0xCCCCCCCC),
>> clang::Decl::print() + 0x33 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\ast\declprinter.cpp, line 96
>> 58>
>> 58>  0x023E2279 (0x00FD30C0 0x00FD30C0 0x00FC6638 0x00C6E770),
>> `anonymous namespace'::ASTPrinter::print() + 0x89 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\frontend\astconsumers.cpp, line 90
>> 58>
>> 58>  0x023521D0 (0x00FCBA38 0x00C6E818 0x00C6E780 0x00FF2AC0),
>> `anonymous namespace'::ASTPrinter::HandleTranslationUnit() + 0x40
>> bytes(s), e:\llvm\llvm\tools\clang\lib\frontend\astconsumers.cpp, line
>> 48 + 0xC byte(s)
>> 58>
>> 58>  0x03130FB8 (0x00FE4E10 0x00000000 0x00000000 0x00C6E79C),
>> clang::ParseAST() + 0x238 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\parse\parseast.cpp, line 154 + 0x18
>> byte(s)
>> 58>
>> 58>  0x022E00B1 (0x00C6E7C4 0xCCCCCCCC 0xCCCCCCCC 0xCCCCCCCC),
>> clang::ASTFrontendAction::ExecuteAction() + 0x101 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\frontend\frontendaction.cpp, line 501 +
>> 0x30 byte(s)
>> 58>
>> 58>  0x022DFCBE (0x00C6E8BC 0x00C6F97C 0xCCCCCCCC 0xCCCCCCCC),
>> clang::FrontendAction::Execute() + 0x7E bytes(s),
>> e:\llvm\llvm\tools\clang\lib\frontend\frontendaction.cpp, line 402 +
>> 0xF byte(s)
>> 58>
>> 58>  0x022AF2B1 (0x00FABE08 0x00C6EE38 0x00C6F97C 0xCCCCCCCC),
>> clang::CompilerInstance::ExecuteAction() + 0x281 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\frontend\compilerinstance.cpp, line 721
>> 58>
>> 58>  0x023EDAE8 (0x00FA6968 0x00C6FD9C 0xCCCCCCCC 0xCCCCCCCC),
>> clang::ExecuteCompilerInvocation() + 0x318 bytes(s),
>> e:\llvm\llvm\tools\clang\lib\frontendtool\executecompilerinvocation.cpp,
>> line 239 + 0x11 byte(s)
>> 58>
>> 58>  0x012C9682 (0x00C6F984 0x00C6F9A4 0x00FA6B90 0x01201361),
>> cc1_main() + 0x2F2 bytes(s),
>> e:\llvm\llvm\tools\clang\tools\driver\cc1_main.cpp, line 112 + 0xE
>> byte(s)
>> 58>
>> 58>  0x012B80B5 (0x0000000A 0x00FA2A98 0x00F9EAF8 0xFF71AEA3), main()
>> + 0x225 bytes(s), e:\llvm\llvm\tools\clang\tools\driver\driver.cpp,
>> line 319 + 0x45 byte(s)
>> 58>
>> 58>  0x03EC2F89 (0x00C6FE00 0x7655338A 0x7EFDE000 0x00C6FE40),
>> __tmainCRTStartup() + 0x199 bytes(s),
>> f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c, line 626 + 0x19 byte(s)
>> 58>
>> 58>  0x03EC30CD (0x7EFDE000 0x00C6FE40 0x778C9F72 0x7EFDE000),
>> mainCRTStartup() + 0xD bytes(s),
>> f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c, line 466
>> 58>
>> 58>  0x7655338A (0x7EFDE000 0x1D841147 0x00000000 0x00000000),
>> BaseThreadInitThunk() + 0x12 bytes(s)
>> 58>
>> 58>  0x778C9F72 (0x03EC30C0 0x7EFDE000 0x00000000 0x00000000),
>> RtlInitializeExceptionChain() + 0x63 bytes(s)
>> 58>
>> 58>  0x778C9F45 (0x03EC30C0 0x7EFDE000 0x00000000 0x00000000),
>> RtlInitializeExceptionChain() + 0x36 bytes(s)
>> 58>
>> 58>
>> 58>
>> 58>  Command 2: "E:/llvm/2013/Debug/bin\FileCheck.EXE"
>> "E:\llvm\llvm\tools\clang\test\PCH\pragma-loop.cpp"
>> 58>  Command 2 Result: 2
>> 58>  Command 2 Output:
>> 58>
>> 58>
>> 58>  Command 2 Stderr:
>> 58>CUSTOMBUILD : FileCheck error : '-' is empty.
>> 58>
>> 58>
>> 58>
>> 58>
>> 58>  --
>> 58>
>> 58>  ********************
>>
>> Some formatting nits (you may want to run clang-format over your
>> patch; http://clang.llvm.org/docs/ClangFormat.html) and one question
>> which may require a comment to be updated. Once those are resolved,
>> along with the crash from above, I think you'll be all set!
>>
>>> Index: include/clang/Basic/Attr.td
>>> ===================================================================
>>> --- include/clang/Basic/Attr.td (revision 208638)
>>> +++ include/clang/Basic/Attr.td (working copy)
>>> @@ -1750,3 +1750,64 @@
>>>  def Unaligned : IgnoredAttr {
>>>    let Spellings = [Keyword<"__unaligned">];
>>>  }
>>> +
>>> +def LoopHint : Attr {
>>> +  // LoopHint Vectorize:
>>> +  //  enable - use vector instructions.
>>> +  //  disable - do not use vector instructions.
>>> +  //  positive value - use vector instructions of the specified width.
>>> +
>>> +  // LoopHint Interleave:
>>> +  //  enable - interleave multiple loop iterations.
>>> +  //  disable - do not interleave multiple loop interactions.
>>> +  //  positive value - interleave the specified number of loop interations.
>>> +
>>> +  // FIXME: Add Pragma spelling to tablegen and
>>> +  // use it here.
>>> +  let Spellings = [Keyword<"loop">];
>>> +
>>> +  // State of the loop optimization specified by the spelling.
>>> +  let Args = [EnumArgument<"Option", "OptionType",
>>> +                          ["vectorize", "interleave"],
>>> +                          ["Vectorize", "Interleave"]>,
>>> +              EnumArgument<"Kind", "KindType",
>>> +                          ["disable", "enable", "value"],
>>> +                          ["Disable", "Enable", "Value"]>,
>>> +              DefaultIntArgument<"Value", 1>];
>>> +
>>> +  let AdditionalMembers = [{
>>> +  // Kinds are compatible if they are not exclusive.
>>> +  static bool isCompatible(int Kind1, int Kind2) {
>>> +    return (Kind1 == Disable) == (Kind2 == Disable);
>>
>> So if Kind1 = Enable and Kind2 = Value, they are compatible? If so,
>> can the comment be updated to make that a bit more explicit
>> (otherwise, it kind of looks like this code may have a bug).
>>
>>> +  }
>>> +
>>> +  static StringRef getOptionName(int Option) {
>>> +    switch (Option) {
>>> +    case Vectorize: return "vectorize";
>>> +    case Interleave: return "interleave";
>>> +    }
>>> +    llvm_unreachable("Unhandled LoopHint option.");
>>> +  }
>>> +
>>> +  static StringRef getKindName(int Kind) {
>>> +    switch (Kind) {
>>> +    case Disable: return "disable";
>>> +    case Enable: return "enable";
>>> +    case Value: return "value";
>>> +    }
>>> +    llvm_unreachable("Unhandled LoopHint kind.");
>>> +  }
>>> +
>>> +  // FIXME: Modify pretty printer to print this pragma
>>> +  void print(raw_ostream &OS, const PrintingPolicy &Policy) const {
>>> +    OS << getOptionName(option) << "(";
>>> +    if (getKind() == Value)
>>> +      OS << value;
>>> +    else
>>> +      OS << getKindName(kind);
>>> +    OS << ")\n";
>>> +  }
>>> +  }];
>>> +
>>> +  let Documentation = [Undocumented];
>>> +}
>>> Index: include/clang/Basic/DiagnosticParseKinds.td
>>> ===================================================================
>>> --- include/clang/Basic/DiagnosticParseKinds.td (revision 208638)
>>> +++ include/clang/Basic/DiagnosticParseKinds.td (working copy)
>>> @@ -884,6 +884,14 @@
>>>    "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">;
>>>  def err_omp_more_one_clause : Error<
>>>    "directive '#pragma omp %0' cannot contain more than one '%1' clause">;
>>> +
>>> +// Pragma loop support.
>>> +def err_pragma_loop_invalid_option : Error<
>>> +  "%select{invalid|missing}0 option%select{ '%1'|}0 in directive "
>>> +  "'#pragma loop'; expected either vectorize or interleave">;
>>> +def err_pragma_loop_invalid_type : Error<
>>> +  "invalid value '%0' in directive '#pragma loop %1'; expected either "
>>> +  "'enable', 'disable', or a positive integer">;
>>>  } // end of Parse Issue category.
>>>
>>>  let CategoryName = "Modules Issue" in {
>>> Index: include/clang/Basic/DiagnosticSemaKinds.td
>>> ===================================================================
>>> --- include/clang/Basic/DiagnosticSemaKinds.td (revision 208638)
>>> +++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
>>> @@ -537,6 +537,13 @@
>>>    "#pragma visibility pop with no matching #pragma visibility push">;
>>>  def note_surrounding_namespace_starts_here : Note<
>>>    "surrounding namespace with visibility attribute starts here">;
>>> +def err_pragma_loop_invalid_value : Error<
>>> +  "expected a positive integer in directive '#pragma loop %0'">;
>>> +def err_pragma_loop_incompatible : Error<
>>> +  "'%0' and '%1' directive option types are incompatible in '#pragma loop %2'">;
>>> +def err_pragma_loop_precedes_nonloop : Error<
>>> +  "expected a for, while, or do-while loop to follow the '#pragma loop' "
>>> +  "directive">;
>>>
>>>  /// Objective-C parser diagnostics
>>>  def err_duplicate_class_def : Error<
>>> Index: include/clang/Basic/TokenKinds.def
>>> ===================================================================
>>> --- include/clang/Basic/TokenKinds.def (revision 208638)
>>> +++ include/clang/Basic/TokenKinds.def (working copy)
>>> @@ -701,6 +701,11 @@
>>>  ANNOTATION(pragma_openmp)
>>>  ANNOTATION(pragma_openmp_end)
>>>
>>> +// Annotations for loop pragma directives #pragma loop ...
>>> +// The lexer produces these so that they only take effect when the parser
>>> +// handles #pragma loop ... directives.
>>> +ANNOTATION(pragma_loop_hint)
>>> +
>>>  // Annotations for module import translated from #include etc.
>>>  ANNOTATION(module_include)
>>>  ANNOTATION(module_begin)
>>> Index: include/clang/Parse/Parser.h
>>> ===================================================================
>>> --- include/clang/Parse/Parser.h (revision 208638)
>>> +++ include/clang/Parse/Parser.h (working copy)
>>> @@ -20,6 +20,7 @@
>>>  #include "clang/Lex/CodeCompletionHandler.h"
>>>  #include "clang/Lex/Preprocessor.h"
>>>  #include "clang/Sema/DeclSpec.h"
>>> +#include "clang/Sema/LoopHint.h"
>>>  #include "clang/Sema/Sema.h"
>>>  #include "llvm/ADT/SmallVector.h"
>>>  #include "llvm/Support/Compiler.h"
>>> @@ -160,6 +161,7 @@
>>>    std::unique_ptr<PragmaHandler> MSConstSeg;
>>>    std::unique_ptr<PragmaHandler> MSCodeSeg;
>>>    std::unique_ptr<PragmaHandler> MSSection;
>>> +  std::unique_ptr<PragmaHandler> LoopHintHandler;
>>>
>>>    std::unique_ptr<CommentHandler> CommentSemaHandler;
>>>
>>> @@ -518,6 +520,10 @@
>>>    /// #pragma clang __debug captured
>>>    StmtResult HandlePragmaCaptured();
>>>
>>> +  /// \brief Handle the annotation token produced for
>>> +  /// #pragma vectorize...
>>> +  LoopHint HandlePragmaLoopHint();
>>> +
>>>    /// GetLookAheadToken - This peeks ahead N tokens and returns that token
>>>    /// without consuming any tokens.  LookAhead(0) returns 'Tok', LookAhead(1)
>>>    /// returns the token after Tok, etc.
>>> @@ -1600,6 +1606,10 @@
>>>    StmtResult ParseReturnStatement();
>>>    StmtResult ParseAsmStatement(bool &msAsm);
>>>    StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
>>> +  StmtResult ParsePragmaLoopHint(StmtVector &Stmts,
>>> +                                 bool OnlyStatement,
>>> +                                 SourceLocation *TrailingElseLoc,
>>> +                                 ParsedAttributesWithRange &Attrs);
>>>
>>>    /// \brief Describes the behavior that should be taken for an __if_exists
>>>    /// block.
>>> Index: include/clang/Sema/LoopHint.h
>>> ===================================================================
>>> --- include/clang/Sema/LoopHint.h (revision 0)
>>> +++ include/clang/Sema/LoopHint.h (working copy)
>>> @@ -0,0 +1,32 @@
>>> +//===--- LoopHint.h - Types for LoopHint ------------------------*- C++ -*-===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>> +//===----------------------------------------------------------------------===//
>>> +
>>> +
>>> +#ifndef LLVM_CLANG_SEMA_LOOPHINT_H
>>> +#define LLVM_CLANG_SEMA_LOOPHINT_H
>>> +
>>> +#include "clang/Basic/IdentifierTable.h"
>>> +#include "clang/Basic/SourceLocation.h"
>>> +#include "clang/Sema/AttributeList.h"
>>> +#include "clang/Sema/Ownership.h"
>>> +
>>> +namespace clang {
>>> +
>>> +/// \brief Loop hint specified by a pragma loop directive.
>>> +struct LoopHint {
>>> +  SourceRange Range;
>>> +  Expr *ValueExpr;
>>> +  IdentifierLoc *LoopLoc;
>>> +  IdentifierLoc *ValueLoc;
>>> +  IdentifierLoc *OptionLoc;
>>> +};
>>> +
>>> +} // end namespace clang
>>> +
>>> +#endif // LLVM_CLANG_SEMA_LOOPHINT_H
>>> Index: lib/AST/StmtPrinter.cpp
>>> ===================================================================
>>> --- lib/AST/StmtPrinter.cpp (revision 208638)
>>> +++ lib/AST/StmtPrinter.cpp (working copy)
>>> @@ -168,19 +168,32 @@
>>>  }
>>>
>>>  void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
>>> -  OS << "[[";
>>>    bool first = true;
>>> -  for (ArrayRef<const Attr*>::iterator it = Node->getAttrs().begin(),
>>> -                                       end = Node->getAttrs().end();
>>> -                                       it != end; ++it) {
>>> -    if (!first) {
>>> -      OS << ", ";
>>> -      first = false;
>>> +  std::string raw_attr_os;
>>> +  llvm::raw_string_ostream AttrOS(raw_attr_os);
>>> +  for (auto I = Node->getAttrs().rbegin(), E = Node->getAttrs().rend();
>>> +       I != E; ++I) {
>>> +    // FIXME: This hack will be removed when printPretty
>>> +    // has been modified to print pretty pragmas.
>>> +    if (dyn_cast<LoopHintAttr>(*I)) {
>>> +      const LoopHintAttr *LHA = cast<LoopHintAttr>(*I);
>>> +      OS << "#pragma loop ";
>>> +      LHA->print(OS, Policy);
>>> +    } else {
>>> +      if (!first) {
>>> +        AttrOS << ", ";
>>> +        first = false;
>>> +      }
>>> +      // TODO: check this
>>> +      (*I)->printPretty(AttrOS, Policy);
>>>      }
>>> -    // TODO: check this
>>> -    (*it)->printPretty(OS, Policy);
>>>    }
>>> -  OS << "]] ";
>>> +
>>> +  // Check to see if any attributes were printed.
>>> +  StringRef AttrStr = AttrOS.str();
>>> +  if (!AttrStr.empty())
>>> +    OS << "[[" << AttrStr << "]] ";
>>> +
>>>    PrintStmt(Node->getSubStmt(), 0);
>>>  }
>>>
>>> Index: lib/CodeGen/CGStmt.cpp
>>> ===================================================================
>>> --- lib/CodeGen/CGStmt.cpp (revision 208638)
>>> +++ lib/CodeGen/CGStmt.cpp (working copy)
>>> @@ -18,6 +18,7 @@
>>>  #include "clang/AST/StmtVisitor.h"
>>>  #include "clang/Basic/PrettyStackTrace.h"
>>>  #include "clang/Basic/TargetInfo.h"
>>> +#include "clang/Sema/LoopHint.h"
>>>  #include "clang/Sema/SemaDiagnostic.h"
>>>  #include "llvm/ADT/StringExtras.h"
>>>  #include "llvm/IR/CallSite.h"
>>> @@ -396,7 +397,23 @@
>>>  }
>>>
>>>  void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
>>> -  EmitStmt(S.getSubStmt());
>>> +  const Stmt *SubStmt = S.getSubStmt();
>>> +  switch (SubStmt->getStmtClass()) {
>>> +  case Stmt::DoStmtClass:
>>> +    EmitDoStmt(cast<DoStmt>(*SubStmt), S.getAttrs());
>>> +    break;
>>> +  case Stmt::ForStmtClass:
>>> +    EmitForStmt(cast<ForStmt>(*SubStmt), S.getAttrs());
>>> +    break;
>>> +  case Stmt::WhileStmtClass:
>>> +    EmitWhileStmt(cast<WhileStmt>(*SubStmt), S.getAttrs());
>>> +    break;
>>> +  case Stmt::CXXForRangeStmtClass:
>>> +    EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*SubStmt), S.getAttrs());
>>> +    break;
>>> +  default:
>>> +    EmitStmt(SubStmt);
>>> +  }
>>>  }
>>>
>>>  void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
>>> @@ -502,7 +519,57 @@
>>>    EmitBlock(ContBlock, true);
>>>  }
>>>
>>> -void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
>>> +void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
>>> +                                      llvm::BranchInst *CondBr,
>>> +                                      ArrayRef<const Attr *> &Attrs) {
>>> +  // Do not continue if there are not hints.
>>> +  if (Attrs.empty())
>>> +    return;
>>> +
>>> +  // Add vectorize hints to the metadata on the conditional branch.
>>> +  // Iterate in reverse so hints are put in the same order they appear.
>>> +  SmallVector<llvm::Value*, 2> Metadata(1);
>>> +  for (auto I = Attrs.rbegin(), E = Attrs.rend(); I != E; ++I) {
>>> +    const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(*I);
>>> +
>>> +    // Skip non loop hint attributes
>>> +    if (!LH)
>>> +      continue;
>>> +
>>> +    LoopHintAttr::OptionType Option = LH->getOption();
>>> +    int ValueInt = LH->getValue();
>>> +    int Kind = LH->getKind();
>>> +
>>> +    llvm::Value *Value;
>>> +    llvm::MDString *Name;
>>> +    const char *MetadataNames[] = { "llvm.vectorizer.width",
>>> +                                    "llvm.vectorizer.unroll" };
>>> +    if (Kind == LoopHintAttr::Enable) {
>>> +      Name = llvm::MDString::get(Context, "llvm.vectorizer.enable");
>>> +      Value = Builder.getTrue();
>>> +    } else {
>>> +      // No need for the disable case because ValueInt is 1 if Kind is disable.
>>> +      Name = llvm::MDString::get(Context, MetadataNames[Option]);
>>> +      Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
>>> +    }
>>> +
>>> +    SmallVector<llvm::Value*, 2> OpValues;
>>> +    OpValues.push_back(Name);
>>> +    OpValues.push_back(Value);
>>> +
>>> +    // Set or overwrite metadata indicated by Name.
>>> +    Metadata.push_back(llvm::MDNode::get(Context, OpValues));
>>> +  }
>>> +
>>> +  // Add llvm.loop MDNode to CondBr.
>>> +  llvm::MDNode *LoopID = llvm::MDNode::get(Context, Metadata);
>>> +  LoopID->replaceOperandWith(0, LoopID); // First op points to itself.
>>> +
>>> +  CondBr->setMetadata("llvm.loop", LoopID);
>>> +}
>>> +
>>> +void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
>>> +                                    ArrayRef<const Attr *> WhileAttrs) {
>>>    RegionCounter Cnt = getPGORegionCounter(&S);
>>>
>>>    // Emit the header for the loop, which will also become
>>> @@ -547,13 +614,17 @@
>>>      llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
>>>      if (ConditionScope.requiresCleanups())
>>>        ExitBlock = createBasicBlock("while.exit");
>>> -    Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock,
>>> -                         PGO.createLoopWeights(S.getCond(), Cnt));
>>> +    llvm::BranchInst *CondBr = Builder.CreateCondBr(
>>> +                               BoolCondVal, LoopBody, ExitBlock,
>>> +                               PGO.createLoopWeights(S.getCond(), Cnt));
>>
>> Formatting.
>>
>>>
>>>      if (ExitBlock != LoopExit.getBlock()) {
>>>        EmitBlock(ExitBlock);
>>>        EmitBranchThroughCleanup(LoopExit);
>>>      }
>>> +
>>> +    // Attach metadata to loop body conditional branch.
>>> +    EmitCondBrHints(LoopBody->getContext(), CondBr, WhileAttrs);
>>>    }
>>>
>>>    // Emit the loop body.  We have to emit this in a cleanup scope
>>> @@ -582,7 +653,8 @@
>>>      SimplifyForwardingBlocks(LoopHeader.getBlock());
>>>  }
>>>
>>> -void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
>>> +void CodeGenFunction::EmitDoStmt(const DoStmt &S,
>>> +                                 ArrayRef<const Attr *> DoAttrs) {
>>>    JumpDest LoopExit = getJumpDestInCurrentScope("do.end");
>>>    JumpDest LoopCond = getJumpDestInCurrentScope("do.cond");
>>>
>>> @@ -619,10 +691,15 @@
>>>        EmitBoolCondBranch = false;
>>>
>>>    // As long as the condition is true, iterate the loop.
>>> -  if (EmitBoolCondBranch)
>>> -    Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock(),
>>> -                         PGO.createLoopWeights(S.getCond(), Cnt));
>>> +  if (EmitBoolCondBranch) {
>>> +    llvm::BranchInst *CondBr = Builder.CreateCondBr(
>>> +                                 BoolCondVal, LoopBody, LoopExit.getBlock(),
>>> +                                 PGO.createLoopWeights(S.getCond(), Cnt));
>>
>> Formatting.
>>
>>>
>>> +    // Attach metadata to loop body conditional branch.
>>> +    EmitCondBrHints(LoopBody->getContext(), CondBr, DoAttrs);
>>> +  }
>>> +
>>>    // Emit the exit block.
>>>    EmitBlock(LoopExit.getBlock());
>>>
>>> @@ -632,7 +709,8 @@
>>>      SimplifyForwardingBlocks(LoopCond.getBlock());
>>>  }
>>>
>>> -void CodeGenFunction::EmitForStmt(const ForStmt &S) {
>>> +void CodeGenFunction::EmitForStmt(const ForStmt &S,
>>> +                                  ArrayRef<const Attr *> ForAttrs) {
>>>    JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
>>>
>>>    RunCleanupsScope ForScope(*this);
>>> @@ -686,9 +764,13 @@
>>>      // C99 6.8.5p2/p4: The first substatement is executed if the expression
>>>      // compares unequal to 0.  The condition must be a scalar type.
>>>      llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
>>> -    Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock,
>>> -                         PGO.createLoopWeights(S.getCond(), Cnt));
>>> +    llvm::BranchInst *CondBr = Builder.CreateCondBr(
>>> +                                 BoolCondVal, ForBody, ExitBlock,
>>> +                                 PGO.createLoopWeights(S.getCond(), Cnt));
>>>
>>> +    // Attach metadata to loop body conditional branch.
>>> +    EmitCondBrHints(ForBody->getContext(), CondBr, ForAttrs);
>>> +
>>>      if (ExitBlock != LoopExit.getBlock()) {
>>>        EmitBlock(ExitBlock);
>>>        EmitBranchThroughCleanup(LoopExit);
>>> @@ -728,7 +810,8 @@
>>>    EmitBlock(LoopExit.getBlock(), true);
>>>  }
>>>
>>> -void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
>>> +void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
>>> +                                          ArrayRef<const Attr *> ForAttrs) {
>>>    JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
>>>
>>>    RunCleanupsScope ForScope(*this);
>>> @@ -761,9 +844,13 @@
>>>    // The body is executed if the expression, contextually converted
>>>    // to bool, is true.
>>>    llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
>>> -  Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock,
>>> -                       PGO.createLoopWeights(S.getCond(), Cnt));
>>> +  llvm::BranchInst *CondBr = Builder.CreateCondBr(BoolCondVal, ForBody,
>>> +                                      ExitBlock,
>>> +                                      PGO.createLoopWeights(S.getCond(), Cnt));
>>
>> Formatting.
>>
>>>
>>> +  // Attach metadata to loop body conditional branch
>>> +  EmitCondBrHints(ForBody->getContext(), CondBr, ForAttrs);
>>> +
>>>    if (ExitBlock != LoopExit.getBlock()) {
>>>      EmitBlock(ExitBlock);
>>>      EmitBranchThroughCleanup(LoopExit);
>>> Index: lib/CodeGen/CodeGenFunction.h
>>> ===================================================================
>>> --- lib/CodeGen/CodeGenFunction.h (revision 208638)
>>> +++ lib/CodeGen/CodeGenFunction.h (working copy)
>>> @@ -1846,9 +1846,16 @@
>>>    void EmitGotoStmt(const GotoStmt &S);
>>>    void EmitIndirectGotoStmt(const IndirectGotoStmt &S);
>>>    void EmitIfStmt(const IfStmt &S);
>>> -  void EmitWhileStmt(const WhileStmt &S);
>>> -  void EmitDoStmt(const DoStmt &S);
>>> -  void EmitForStmt(const ForStmt &S);
>>> +
>>> +  void EmitCondBrHints(llvm::LLVMContext &Context,
>>> +                       llvm::BranchInst *CondBr,
>>> +                       ArrayRef<const Attr *> &Attrs);
>>> +  void EmitWhileStmt(const WhileStmt &S,
>>> +                     ArrayRef<const Attr *> Attrs = ArrayRef<const Attr *>());
>>> +  void EmitDoStmt(const DoStmt &S,
>>> +                  ArrayRef<const Attr *> Attrs = ArrayRef<const Attr *>());
>>> +  void EmitForStmt(const ForStmt &S,
>>> +                   ArrayRef<const Attr *> Attrs = ArrayRef<const Attr *>());
>>>    void EmitReturnStmt(const ReturnStmt &S);
>>>    void EmitDeclStmt(const DeclStmt &S);
>>>    void EmitBreakStmt(const BreakStmt &S);
>>> @@ -1872,7 +1879,8 @@
>>>
>>>    void EmitCXXTryStmt(const CXXTryStmt &S);
>>>    void EmitSEHTryStmt(const SEHTryStmt &S);
>>> -  void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
>>> +  void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
>>> +                       ArrayRef<const Attr *> Attrs = ArrayRef<const Attr *>());
>>
>> Formatting.
>>
>>>
>>>    llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
>>>    llvm::Function *GenerateCapturedStmtFunction(const CapturedDecl *CD,
>>> Index: lib/Parse/ParsePragma.cpp
>>> ===================================================================
>>> --- lib/Parse/ParsePragma.cpp (revision 208638)
>>> +++ lib/Parse/ParsePragma.cpp (working copy)
>>> @@ -15,6 +15,7 @@
>>>  #include "clang/Lex/Preprocessor.h"
>>>  #include "clang/Parse/ParseDiagnostic.h"
>>>  #include "clang/Parse/Parser.h"
>>> +#include "clang/Sema/LoopHint.h"
>>>  #include "clang/Sema/Scope.h"
>>>  #include "llvm/ADT/StringSwitch.h"
>>>  using namespace clang;
>>> @@ -131,6 +132,12 @@
>>>                      Token &FirstToken) override;
>>>  };
>>>
>>> +struct PragmaLoopHintHandler : public PragmaHandler {
>>> +  PragmaLoopHintHandler() : PragmaHandler("loop") {}
>>> +  void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
>>> +                    Token &FirstToken) override;
>>> +};
>>> +
>>>  }  // end namespace
>>>
>>>  void Parser::initializePragmaHandlers() {
>>> @@ -195,6 +202,9 @@
>>>      MSSection.reset(new PragmaMSPragma("section"));
>>>      PP.AddPragmaHandler(MSSection.get());
>>>    }
>>> +
>>> +  LoopHintHandler.reset(new PragmaLoopHintHandler());
>>> +  PP.AddPragmaHandler(LoopHintHandler.get());
>>>  }
>>>
>>>  void Parser::resetPragmaHandlers() {
>>> @@ -249,6 +259,10 @@
>>>
>>>    PP.RemovePragmaHandler("STDC", FPContractHandler.get());
>>>    FPContractHandler.reset();
>>> +
>>> +  PP.RemovePragmaHandler(LoopHintHandler.get());
>>> +  LoopHintHandler.reset();
>>> +
>>>  }
>>>
>>>  /// \brief Handle the annotation token produced for #pragma unused(...)
>>> @@ -570,6 +584,40 @@
>>>        DiagnosticsEngine::Error, "'#pragma %0' not implemented.");
>>>  }
>>>
>>> +struct PragmaLoopHintInfo {
>>> +  Token Loop;
>>> +  Token Value;
>>> +  Token Option;
>>> +};
>>> +
>>> +LoopHint Parser::HandlePragmaLoopHint() {
>>> +  assert(Tok.is(tok::annot_pragma_loop_hint));
>>> +  PragmaLoopHintInfo *Info =
>>> +    static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
>>> +
>>> +  LoopHint Hint;
>>> +  Hint.LoopLoc = IdentifierLoc::create(Actions.Context,
>>> +                                       Info->Loop.getLocation(),
>>> +                                       Info->Loop.getIdentifierInfo());
>>> +  Hint.OptionLoc = IdentifierLoc::create(Actions.Context,
>>> +                                         Info->Option.getLocation(),
>>> +                                         Info->Option.getIdentifierInfo());
>>> +  Hint.ValueLoc = IdentifierLoc::create(Actions.Context,
>>> +                                        Info->Value.getLocation(),
>>> +                                        Info->Value.getIdentifierInfo());
>>> +  Hint.Range = SourceRange(Info->Option.getLocation(),
>>> +                           Info->Value.getLocation());
>>> +
>>> +  // FIXME: We should support template parameters for the loop hint value.
>>> +  // See bug report #19610
>>> +  if (Info->Value.is(tok::numeric_constant))
>>> +    Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
>>> +  else
>>> +    Hint.ValueExpr = nullptr;
>>> +
>>> +  return Hint;
>>> +}
>>> +
>>>  // #pragma GCC visibility comes in two variants:
>>>  //   'push' '(' [visibility] ')'
>>>  //   'pop'
>>> @@ -1531,3 +1579,108 @@
>>>
>>>    Actions.ActOnPragmaMSComment(Kind, ArgumentString);
>>>  }
>>> +
>>> +/// \brief Handle the \#pragma vectorize hint.
>>> +///  #pragma 'loop' loop-hints
>>> +///
>>> +///  loop-hints:
>>> +///    loop-hint loop-hints[opt]
>>> +///
>>> +///  loop-hint:
>>> +///    'vectorize' '(' loop-hint-value ')'
>>> +///    'interleave' '(' loop-hint-value ')'
>>> +///
>>> +///  loop-hint-value:
>>> +///    'enable'
>>> +///    'disable'
>>> +///    constant-expression
>>> +///
>>> +/// Specifying vectorize(enable) or vectorize(_value_) instructs llvm to
>>> +/// try vectorizing the instructions of the loop it precedes. Specifying
>>> +/// interleave(enable) or interleave(_value_) instructs llvm to try interleaving
>>> +/// multiple iterations of the loop it precedes. The _value_ indicates the
>>> +/// width of the vector instructions or the number of iterations of the loop
>>> +/// that should be interleaved. Consequently, a value of 1 or disable prevents
>>> +/// the optimization, even if it is possible and profitable, and 0 is invalid.
>>> +/// The loop vectorizer currently only works on inner loops.
>>> +///
>>> +void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
>>> +                                         PragmaIntroducerKind Introducer,
>>> +                                         Token &Tok) {
>>> +  Token Loop = Tok;
>>> +  SmallVector <Token, 1> TokenList;
>>> +
>>> +  // Lex the optimization option and verify it is an identifier.
>>> +  PP.Lex(Tok);
>>> +  if (Tok.isNot(tok::identifier)) {
>>> +    PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
>>> +      << /*InvalidOption*/true << "";
>>> +    return;
>>> +  }
>>> +
>>> +  while(Tok.is(tok::identifier)) {
>>> +    Token Option = Tok;
>>> +    StringRef OptionName = Tok.getIdentifierInfo()->getName();
>>> +
>>> +    if (OptionName != "vectorize" && OptionName != "interleave") {
>>> +      PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
>>> +        << /*InvalidOption*/false << OptionName;
>>> +      return;
>>> +    }
>>> +
>>> +    // Read '('
>>> +    PP.Lex(Tok);
>>> +    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) && Tok.isNot(tok::numeric_constant)) {
>>> +      PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_type)
>>> +        << Tok.getName();
>>> +      return;
>>> +    }
>>> +
>>> +    Token Value = Tok;
>>> +
>>> +    // Read ')'
>>> +    PP.Lex(Tok);
>>> +    if (Tok.isNot(tok::r_paren)) {
>>> +      PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
>>> +      return;
>>> +    }
>>> +
>>> +    // Get next optimization option.
>>> +    PP.Lex(Tok);
>>> +
>>> +    PragmaLoopHintInfo *Info =
>>> +      (PragmaLoopHintInfo*) PP.getPreprocessorAllocator().Allocate(
>>> +        sizeof(PragmaLoopHintInfo), llvm::alignOf<PragmaLoopHintInfo>());
>>> +
>>> +    Info->Loop = Loop;
>>> +    Info->Option = Option;
>>> +    Info->Value = Value;
>>> +
>>> +    // Generate the vectorization hint token.
>>> +    Token LoopHintTok;
>>> +    LoopHintTok.startToken();
>>> +    LoopHintTok.setKind(tok::annot_pragma_loop_hint);
>>> +    LoopHintTok.setLocation(Loop.getLocation());
>>> +    LoopHintTok.setAnnotationValue(static_cast<void*>(Info));
>>> +    TokenList.push_back(LoopHintTok);
>>> +  }
>>> +
>>> +  if (Tok.isNot(tok::eod)) {
>>> +    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
>>> +      << "loop";
>>> +    return;
>>> +  }
>>> +
>>> +  Token *TokenArray = new Token[TokenList.size()];
>>> +  std::copy(TokenList.begin(), TokenList.end(), TokenArray);
>>> +
>>> +  PP.EnterTokenStream(TokenArray, TokenList.size(),
>>> +                      /*DisableMacroExpansion=*/false,
>>> +                      /*OwnsTokens=*/true);
>>> +}
>>> Index: lib/Parse/ParseStmt.cpp
>>> ===================================================================
>>> --- lib/Parse/ParseStmt.cpp (revision 208638)
>>> +++ lib/Parse/ParseStmt.cpp (working copy)
>>> @@ -15,11 +15,13 @@
>>>  #include "clang/Parse/Parser.h"
>>>  #include "RAIIObjectsForParser.h"
>>>  #include "clang/AST/ASTContext.h"
>>> +#include "clang/Basic/Attributes.h"
>>>  #include "clang/Basic/Diagnostic.h"
>>>  #include "clang/Basic/PrettyStackTrace.h"
>>>  #include "clang/Basic/SourceManager.h"
>>>  #include "clang/Basic/TargetInfo.h"
>>>  #include "clang/Sema/DeclSpec.h"
>>> +#include "clang/Sema/LoopHint.h"
>>>  #include "clang/Sema/PrettyDeclStackTrace.h"
>>>  #include "clang/Sema/Scope.h"
>>>  #include "clang/Sema/TypoCorrection.h"
>>> @@ -357,6 +359,10 @@
>>>      ProhibitAttributes(Attrs);
>>>      HandlePragmaMSPragma();
>>>      return StmtEmpty();
>>> +
>>> +  case tok::annot_pragma_loop_hint:
>>> +    ProhibitAttributes(Attrs);
>>> +    return ParsePragmaLoopHint(Stmts, OnlyStatement, TrailingElseLoc, Attrs);
>>>    }
>>>
>>>    // If we reached this code, the statement must end in a semicolon.
>>> @@ -1751,6 +1757,43 @@
>>>    return Actions.ActOnReturnStmt(ReturnLoc, R.take(), getCurScope());
>>>  }
>>>
>>> +StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
>>> +                                       bool OnlyStatement,
>>> +                                       SourceLocation *TrailingElseLoc,
>>> +                                       ParsedAttributesWithRange &Attrs) {
>>> +  // Create temporary attribute list.
>>> +  ParsedAttributesWithRange TempAttrs(AttrFactory);
>>> +
>>> +  // Get vectorize hints and consume annotated token.
>>> +  while (Tok.is(tok::annot_pragma_loop_hint)) {
>>> +    LoopHint Hint = HandlePragmaLoopHint();
>>> +    ConsumeToken();
>>> +
>>> +    if (!Hint.LoopLoc ||
>>> +        !Hint.OptionLoc ||
>>> +        !Hint.ValueLoc)
>>> +      continue;
>>> +
>>> +    ArgsUnion ArgHints[] = {Hint.OptionLoc,
>>> +                            Hint.ValueLoc,
>>> +                            ArgsUnion(Hint.ValueExpr)};
>>> +    // FIXME: Replace AS_Keyword with Pragma spelling AS_Pragma.
>>> +    TempAttrs.addNew(Hint.LoopLoc->Ident, Hint.Range,
>>> +                     0, Hint.LoopLoc->Loc,
>>> +                     ArgHints, 3,
>>> +                     AttributeList::AS_Keyword);
>>> +  }
>>> +
>>> +  // Get the next statement.
>>> +  MaybeParseCXX11Attributes(Attrs);
>>> +
>>> +  StmtResult S = ParseStatementOrDeclarationAfterAttributes(Stmts,
>>> +                  OnlyStatement, TrailingElseLoc, Attrs);
>>> +
>>> +  Attrs.takeAllFrom(TempAttrs);
>>> +  return S;
>>> +}
>>> +
>>>  namespace {
>>>    class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
>>>      Parser &TheParser;
>>> Index: lib/Sema/SemaStmtAttr.cpp
>>> ===================================================================
>>> --- lib/Sema/SemaStmtAttr.cpp (revision 208638)
>>> +++ lib/Sema/SemaStmtAttr.cpp (working copy)
>>> @@ -16,6 +16,7 @@
>>>  #include "clang/Basic/SourceManager.h"
>>>  #include "clang/Sema/DelayedDiagnostic.h"
>>>  #include "clang/Sema/Lookup.h"
>>> +#include "clang/Sema/LoopHint.h"
>>>  #include "clang/Sema/ScopeInfo.h"
>>>  #include "llvm/ADT/StringExtras.h"
>>>
>>> @@ -42,7 +43,83 @@
>>>                                             A.getAttributeSpellingListIndex());
>>>  }
>>>
>>> +static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
>>> +                                SourceRange Range) {
>>> +  if (St->getStmtClass() != Stmt::DoStmtClass &&
>>> +      St->getStmtClass() != Stmt::ForStmtClass &&
>>> +      St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
>>> +      St->getStmtClass() != Stmt::WhileStmtClass) {
>>> +    S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop);
>>> +    return nullptr;
>>> +  }
>>>
>>> +  IdentifierLoc *OptionLoc = A.getArgAsIdent(0);
>>> +  IdentifierInfo *OptionInfo = OptionLoc->Ident;
>>> +  IdentifierLoc *ValueLoc = A.getArgAsIdent(1);
>>> +  IdentifierInfo *ValueInfo = ValueLoc->Ident;
>>> +  Expr *ValueExpr = A.getArgAsExpr(2);
>>> +
>>> +  assert(OptionInfo && "Attribute must have valid option info.");
>>> +
>>> +  LoopHintAttr::OptionType Option = LoopHintAttr::Vectorize;
>>> +  if (OptionInfo->getName() == "vectorize")
>>> +    Option = LoopHintAttr::Vectorize;
>>> +  else if (OptionInfo->getName() == "interleave")
>>> +    Option = LoopHintAttr::Interleave;
>>> +
>>> +  LoopHintAttr::KindType Kind = LoopHintAttr::Value;
>>> +  if (ValueInfo && ValueInfo->getName() == "enable")
>>> +    Kind = LoopHintAttr::Enable;
>>> +  else if (ValueInfo && ValueInfo->getName() == "disable")
>>> +    Kind = LoopHintAttr::Disable;
>>> +
>>> +  // FIXME: We should support template parameters for the loop hint value.
>>> +  // See bug report #19610
>>> +  int ValueInt = 1; // No vectorization/interleaving when kind set to disable.
>>> +  if (Kind == LoopHintAttr::Value) {
>>> +    llvm::APSInt ValueAPS;
>>> +    if(!ValueExpr ||
>>> +       !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
>>> +       (ValueInt = ValueAPS.getSExtValue()) < 1) {
>>> +      S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value)
>>> +        << LoopHintAttr::getOptionName(Option);
>>> +      return nullptr;
>>> +    }
>>> +  }
>>> +
>>> +  return LoopHintAttr::CreateImplicit(S.Context,
>>> +                                      Option, Kind, ValueInt, A.getRange());
>>> +}
>>> +
>>> +static void CheckForIncompatibleAttributes(Sema &S,
>>> +                                          SmallVectorImpl<const Attr*> &Attrs) {
>>
>> Formatting.
>>
>>> +  int PrevKind[2] = {-1, -1};
>>> +
>>> +  // FIXME: Attrs are stored in the reverse order than they appear.
>>> +  for (auto I = Attrs.rbegin(), E = Attrs.rend(); I != E; ++I) {
>>> +    const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(*I);
>>> +
>>> +    // Skip non loop hint attributes
>>> +    if (!LH)
>>> +      continue;
>>> +
>>> +    int Option = LH->getOption();
>>> +    int Kind = LH->getKind();
>>> +    SourceLocation ValueLoc = LH->getRange().getEnd();
>>> +
>>> +    // We only need to check that a loop hint is compatible with the
>>> +    // previous loop hint to ensure that all hints are compatible.
>>> +    if (PrevKind[Option] != -1 &&
>>> +        !LoopHintAttr::isCompatible(PrevKind[Option], Kind)) {
>>> +      S.Diag(ValueLoc, diag::err_pragma_loop_incompatible)
>>> +        << LoopHintAttr::getKindName(PrevKind[Option])
>>> +        << LoopHintAttr::getKindName(Kind)
>>> +        << LoopHintAttr::getOptionName(Option);
>>> +    }
>>> +    PrevKind[Option] = Kind;
>>> +  }
>>> +}
>>> +
>>>  static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
>>>                                    SourceRange Range) {
>>>    switch (A.getKind()) {
>>> @@ -53,6 +130,8 @@
>>>      return 0;
>>>    case AttributeList::AT_FallThrough:
>>>      return handleFallThroughAttr(S, St, A, Range);
>>> +  case AttributeList::AT_LoopHint:
>>> +    return handleLoopHintAttr(S, St, A, Range);
>>>    default:
>>>      // if we're here, then we parsed a known attribute, but didn't recognize
>>>      // it as a statement attribute => it is declaration attribute
>>> @@ -65,11 +144,14 @@
>>>  StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
>>>                                         SourceRange Range) {
>>>    SmallVector<const Attr*, 8> Attrs;
>>> +  // FIXME: Attrs are stored in the reverse order than they appear.
>>>    for (const AttributeList* l = AttrList; l; l = l->getNext()) {
>>>      if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range))
>>>        Attrs.push_back(a);
>>>    }
>>>
>>> +  CheckForIncompatibleAttributes(*this, Attrs);
>>> +
>>>    if (Attrs.empty())
>>>      return S;
>>>
>>> Index: test/CodeGen/pragma-loop.cpp
>>> ===================================================================
>>> --- test/CodeGen/pragma-loop.cpp (revision 0)
>>> +++ test/CodeGen/pragma-loop.cpp (working copy)
>>> @@ -0,0 +1,120 @@
>>> +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s
>>> +
>>> +// CHECK: br i1 %cmp, label %while.body, label %while.end, !llvm.loop !1
>>> +// CHECK: br i1 %cmp, label %do.body, label %do.end, !llvm.loop !5
>>> +// CHECK: br i1 %cmp, label %for.body, label %for.end, !llvm.loop !7
>>> +// CHECK: br i1 %cmp, label %for.body, label %for.end, !llvm.loop !8
>>> +// CHECK: br i1 %cmp, label %for.body, label %for.end, !llvm.loop !11
>>> +// CHECK: br i1 %cmp, label %for.body, label %for.end, !llvm.loop !13
>>> +// CHECK: br i1 %cmp, label %for.body, label %for.end, !llvm.loop !14
>>> +// CHECK: br i1 %cmp, label %for.body, label %for.end, !llvm.loop !16
>>> +
>>> +// CHECK: !1 = metadata !{metadata !1, metadata !2, metadata !3, metadata !4}
>>> +// CHECK: !2 = metadata !{metadata !"llvm.vectorizer.enable", i1 true}
>>> +// CHECK: !3 = metadata !{metadata !"llvm.vectorizer.unroll", i32 4}
>>> +// CHECK: !4 = metadata !{metadata !"llvm.vectorizer.width", i32 4}
>>> +// CHECK: !5 = metadata !{metadata !5, metadata !6, metadata !3}
>>> +// CHECK: !6 = metadata !{metadata !"llvm.vectorizer.width", i32 8}
>>> +// CHECK: !7 = metadata !{metadata !7, metadata !2, metadata !3}
>>> +// CHECK: !8 = metadata !{metadata !8, metadata !9, metadata !10}
>>> +// CHECK: !9 = metadata !{metadata !"llvm.vectorizer.width", i32 2}
>>> +// CHECK: !10 = metadata !{metadata !"llvm.vectorizer.unroll", i32 2}
>>> +// CHECK: !11 = metadata !{metadata !11, metadata !12}
>>> +// CHECK: !12 = metadata !{metadata !"llvm.vectorizer.width", i32 1}
>>> +// CHECK: !13 = metadata !{metadata !13, metadata !9, metadata !10}
>>> +// CHECK: !14 = metadata !{metadata !14, metadata !6, metadata !15}
>>> +// CHECK: !15 = metadata !{metadata !"llvm.vectorizer.unroll", i32 8}
>>> +// CHECK: !16 = metadata !{metadata !16, metadata !9, metadata !10}
>>> +
>>> +// Verify while loop is recognized after sequence of pragma loop directives.
>>> +void while_test(int *List, int Length) {
>>> +  int i = 0;
>>> +
>>> +  #pragma loop vectorize(enable)
>>> +  #pragma loop interleave(4)
>>> +  #pragma loop vectorize(4)
>>> +  while(i < Length) {
>>> +    List[i] = i*2;
>>> +    i++;
>>> +  }
>>> +}
>>> +
>>> +// Verify do loop is recognized after multi-option pragma loop directive.
>>> +void do_test(int *List, int Length) {
>>> +  int i = 0;
>>> +
>>> +  #pragma loop vectorize(8) interleave(4)
>>> +  do {
>>> +    List[i] = i*2;
>>> +    i++;
>>> +  } while (i < Length);
>>> +}
>>> +
>>> +// Verify for loop is recognized after sequence of pragma loop directives.
>>> +void for_test(int *List, int Length) {
>>> +  #pragma loop interleave(enable)
>>> +  #pragma loop interleave(4)
>>> +  for(int i = 0; i < Length; i++) {
>>> +    List[i] = i*2;
>>> +  }
>>> +}
>>> +
>>> +// Verify c++11 for range loop is recognized after
>>> +// sequence of pragma loop directives.
>>> +void for_range_test() {
>>> +  double List[100];
>>> +
>>> +  #pragma loop vectorize(2) interleave(2)
>>> +  for (int i : List) {
>>> +    List[i] = i;
>>> +  }
>>> +}
>>> +
>>> +// Verify disable pragma loop directive generates correct metadata
>>> +void disable_test(int *List, int Length) {
>>> +  #pragma loop vectorize(disable)
>>> +  for(int i = 0; i < Length; i++) {
>>> +    List[i] = i*2;
>>> +  }
>>> +}
>>> +
>>> +#define VECWIDTH 2
>>> +#define INTERLEAVE 2
>>> +
>>> +// Verify defines are correctly resolved in pragma loop directive
>>> +void for_define_test(int *List, int Length, int Value) {
>>> +  #pragma loop vectorize(VECWIDTH) interleave(INTERLEAVE)
>>> +  for(int i = 0; i < Length; i++) {
>>> +    List[i] = i*Value;
>>> +  }
>>> +}
>>> +
>>> +// Verify metadata is generated when template is used.
>>> +template <typename A>
>>> +void for_template_test(A *List, int Length, A Value) {
>>> +
>>> +  #pragma loop vectorize(8) interleave(8)
>>> +  for(int i = 0; i < Length; i++) {
>>> +    List[i] = i*Value;
>>> +  }
>>> +}
>>> +
>>> +// Verify define is resolved correctly when template is used.
>>> +template <typename A>
>>> +void for_template_define_test(A *List, int Length, A Value) {
>>> +  #pragma loop vectorize(VECWIDTH) interleave(INTERLEAVE)
>>> +  for(int i = 0; i < Length; i++) {
>>> +    List[i] = i*Value;
>>> +  }
>>> +}
>>> +
>>> +#undef VECWIDTH
>>> +#undef INTERLEAVE
>>> +
>>> +// Use templates defined above. Test verifies metadata is generated correctly.
>>> +void template_test(double *List, int Length) {
>>> +  double Value = 10;
>>> +
>>> +  for_template_test<double>(List, Length, Value);
>>> +  for_template_define_test<double>(List, Length, Value);
>>> +}
>>> Index: test/PCH/pragma-loop.cpp
>>> ===================================================================
>>> --- test/PCH/pragma-loop.cpp (revision 0)
>>> +++ test/PCH/pragma-loop.cpp (working copy)
>>> @@ -0,0 +1,59 @@
>>> +// RUN: %clang_cc1 -emit-pch -o %t.a %s
>>> +// RUN: %clang_cc1 -include-pch %t.a %s -ast-print -o - | FileCheck %s
>>> +
>>> +// CHECK: #pragma loop vectorize(8)
>>> +// CHECK: #pragma loop interleave(4)
>>> +// CHECK: #pragma loop vectorize(disable)
>>> +// CHECK: #pragma loop interleave(enable)
>>> +// CHECK: #pragma loop vectorize(enable)
>>> +// CHECK: #pragma loop interleave(disable)
>>> +
>>> +#ifndef HEADER
>>> +#define HEADER
>>> +
>>> +class pragma_test {
>>> +public:
>>> +  inline void run1(int *List, int Length) {
>>> +    int i = 0;
>>> +    #pragma loop vectorize(8)
>>> +    #pragma loop interleave(4)
>>> +    while (i < Length) {
>>> +      List[i] = i;
>>> +      i++;
>>> +    }
>>> +  }
>>> +
>>> +  inline void run2(int *List, int Length) {
>>> +    int i = 0;
>>> +    #pragma loop vectorize(disable)
>>> +    #pragma loop interleave(enable)
>>> +    while (i-1 < Length) {
>>> +      List[i] = i;
>>> +      i++;
>>> +    }
>>> +  }
>>> +
>>> +  inline void run3(int *List, int Length) {
>>> +    int i = 0;
>>> +    #pragma loop vectorize(enable)
>>> +    #pragma loop interleave(disable)
>>> +    while (i-3 < Length) {
>>> +      List[i] = i;
>>> +      i++;
>>> +    }
>>> +  }
>>> +};
>>> +
>>> +#else
>>> +
>>> +void test() {
>>> +  int List[100];
>>> +
>>> +  pragma_test pt;
>>> +
>>> +  pt.run1(List, 100);
>>> +  pt.run2(List, 100);
>>> +  pt.run3(List, 100);
>>> +}
>>> +
>>> +#endif
>>> Index: test/Parser/pragma-loop-ast.cpp
>>> ===================================================================
>>> --- test/Parser/pragma-loop-ast.cpp (revision 0)
>>> +++ test/Parser/pragma-loop-ast.cpp (working copy)
>>> @@ -0,0 +1,33 @@
>>> +// RUN: %clang_cc1 -ast-print %s | FileCheck %s
>>> +
>>> +// CHECK: #pragma loop vectorize(4)
>>> +// CHECK: #pragma loop interleave(8)
>>> +// CHECK: #pragma loop vectorize(enable)
>>> +// CHECK: #pragma loop interleave(disable)
>>> +// CHECK: #pragma loop vectorize(disable)
>>> +// CHECK: #pragma loop interleave(enable)
>>> +
>>> +void test(int *List, int Length)
>>> +{
>>> +  int i = 0;
>>> +  #pragma loop vectorize(4)
>>> +  #pragma loop interleave(8)
>>> +  while (i < Length) {
>>> +    List[i] = i * 2;
>>> +    i++;
>>> +  }
>>> +
>>> +  #pragma loop vectorize(enable)
>>> +  #pragma loop interleave(disable)
>>> +  while (i-1 < Length) {
>>> +    List[i] = i * 2;
>>> +    i++;
>>> +  }
>>> +
>>> +  #pragma loop vectorize(disable)
>>> +  #pragma loop interleave(enable)
>>> +  while (i-2 < Length) {
>>> +    List[i] = i * 2;
>>> +    i++;
>>> +  }
>>> +}
>>> Index: test/Parser/pragma-loop.cpp
>>> ===================================================================
>>> --- test/Parser/pragma-loop.cpp (revision 0)
>>> +++ test/Parser/pragma-loop.cpp (working copy)
>>> @@ -0,0 +1,105 @@
>>> +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
>>> +
>>> +// Note that this puts the expected lines before the directives to work around
>>> +// limitations in the -verify mode.
>>> +
>>> +void test(int *List, int Length)
>>> +{
>>> +  int i = 0;
>>> +
>>> +  #pragma loop vectorize(4)
>>> +  #pragma loop interleave(8)
>>> +  while (i+1 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +  #pragma loop vectorize(enable)
>>> +  #pragma loop interleave(enable)
>>> +  while (i < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +  #pragma loop vectorize(disable)
>>> +  #pragma loop interleave(disable)
>>> +  while (i-1 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +  #pragma loop vectorize(4) interleave(8)
>>> +  while (i-2 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +  #pragma loop interleave(16)
>>> +  while (i-3 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +  int VList[Length];
>>> +  #pragma loop vectorize(disable) interleave(disable)
>>> +  for (int j : VList) {
>>> +    VList[j] = List[j];
>>> +  }
>>> +
>>> +/* expected-error {{expected '('}} */ #pragma loop vectorize
>>> +/* expected-error {{expected '('}} */ #pragma loop interleave
>>> +
>>> +/* expected-error {{expected ')'}} */ #pragma loop vectorize(4
>>> +/* expected-error {{expected ')'}} */ #pragma loop interleave(4
>>> +
>>> +/* expected-error {{missing option in directive '#pragma loop'}} */ #pragma loop
>>> +/* expected-error {{invalid option 'badkeyword' in directive '#pragma loop'}} */ #pragma loop badkeyword
>>> +/* expected-error {{invalid option 'badkeyword' in directive '#pragma loop'}} */ #pragma loop badkeyword(2)
>>> +/* expected-error {{invalid option 'badkeyword' in directive '#pragma loop'}} */ #pragma loop vectorize(4) badkeyword(4)
>>> +/* expected-warning {{extra tokens at end of '#pragma loop'}} */ #pragma loop vectorize(4) ,
>>> +
>>> +  while (i-4 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +/* expected-error {{expected a positive integer in directive '#pragma loop vectorize'}} */ #pragma loop vectorize(0)
>>> +/* expected-error {{expected a positive integer in directive '#pragma loop interleave'}} */ #pragma loop interleave(0)
>>> +  while (i-5 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +/* expected-error {{expected a positive integer in directive '#pragma loop vectorize'}} */ #pragma loop vectorize(3000000000)
>>> +/* expected-error {{expected a positive integer in directive '#pragma loop interleave'}} */ #pragma loop interleave(3000000000)
>>> +  while (i-6 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +/* expected-error {{expected a positive integer in directive '#pragma loop vectorize'}} */ #pragma loop vectorize(badvalue)
>>> +/* expected-error {{expected a positive integer in directive '#pragma loop interleave'}} */ #pragma loop interleave(badvalue)
>>> +  while (i-7 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +#pragma loop vectorize(enable)
>>> +/* expected-error {{expected a for, while, or do-while loop to follow the '#pragma loop' directive}} */ int j = Length;
>>> +  List[0] = List[1];
>>> +
>>> +  while (j-1 < Length) {
>>> +    List[j] = j;
>>> +  }
>>> +
>>> +#pragma loop vectorize(4)
>>> +/* expected-error {{'value' and 'disable' directive option types are incompatible in '#pragma loop vectorize'}} */ #pragma loop vectorize(disable)
>>> +  while (i-8 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +#pragma loop interleave(enable)
>>> +/* expected-error {{'enable' and 'disable' directive option types are incompatible in '#pragma loop interleave'}} */ #pragma loop interleave(disable)
>>> +  while (i-9 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +#pragma loop vectorize(disable)
>>> +/* expected-error {{'disable' and 'value' directive option types are incompatible in '#pragma loop vectorize'}} */ #pragma loop vectorize(4)
>>> +  while (i-10 < Length) {
>>> +    List[i] = i;
>>> +  }
>>> +
>>> +#pragma loop interleave(enable)
>>> +/* expected-error {{expected statement}} */ }
>>>
>>
>> ~Aaron




More information about the cfe-commits mailing list