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