1 //===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CGLoopInfo.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/Attr.h" 12 #include "llvm/IR/BasicBlock.h" 13 #include "llvm/IR/CFG.h" 14 #include "llvm/IR/Constants.h" 15 #include "llvm/IR/InstrTypes.h" 16 #include "llvm/IR/Instructions.h" 17 #include "llvm/IR/Metadata.h" 18 using namespace clang::CodeGen; 19 using namespace llvm; 20 21 static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs, 22 const llvm::DebugLoc &StartLoc, 23 const llvm::DebugLoc &EndLoc, MDNode *&AccGroup) { 24 25 if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 && 26 Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 && 27 Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled && 28 Attrs.PipelineInitiationInterval == 0 && 29 Attrs.VectorizeEnable == LoopAttributes::Unspecified && 30 Attrs.UnrollEnable == LoopAttributes::Unspecified && 31 Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified && 32 Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc && 33 !EndLoc) 34 return nullptr; 35 36 SmallVector<Metadata *, 4> Args; 37 // Reserve operand 0 for loop id self reference. 38 auto TempNode = MDNode::getTemporary(Ctx, None); 39 Args.push_back(TempNode.get()); 40 41 // If we have a valid start debug location for the loop, add it. 42 if (StartLoc) { 43 Args.push_back(StartLoc.getAsMDNode()); 44 45 // If we also have a valid end debug location for the loop, add it. 46 if (EndLoc) 47 Args.push_back(EndLoc.getAsMDNode()); 48 } 49 50 // Setting vectorize.width 51 if (Attrs.VectorizeWidth > 0) { 52 Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.width"), 53 ConstantAsMetadata::get(ConstantInt::get( 54 Type::getInt32Ty(Ctx), Attrs.VectorizeWidth))}; 55 Args.push_back(MDNode::get(Ctx, Vals)); 56 } 57 58 // Setting interleave.count 59 if (Attrs.InterleaveCount > 0) { 60 Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.interleave.count"), 61 ConstantAsMetadata::get(ConstantInt::get( 62 Type::getInt32Ty(Ctx), Attrs.InterleaveCount))}; 63 Args.push_back(MDNode::get(Ctx, Vals)); 64 } 65 66 // Setting unroll.count 67 if (Attrs.UnrollCount > 0) { 68 Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"), 69 ConstantAsMetadata::get(ConstantInt::get( 70 Type::getInt32Ty(Ctx), Attrs.UnrollCount))}; 71 Args.push_back(MDNode::get(Ctx, Vals)); 72 } 73 74 // Setting unroll_and_jam.count 75 if (Attrs.UnrollAndJamCount > 0) { 76 Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll_and_jam.count"), 77 ConstantAsMetadata::get(ConstantInt::get( 78 Type::getInt32Ty(Ctx), Attrs.UnrollAndJamCount))}; 79 Args.push_back(MDNode::get(Ctx, Vals)); 80 } 81 82 // Setting vectorize.enable 83 if (Attrs.VectorizeEnable != LoopAttributes::Unspecified) { 84 Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.enable"), 85 ConstantAsMetadata::get(ConstantInt::get( 86 Type::getInt1Ty(Ctx), (Attrs.VectorizeEnable == 87 LoopAttributes::Enable)))}; 88 Args.push_back(MDNode::get(Ctx, Vals)); 89 } 90 91 // Setting unroll.full or unroll.disable 92 if (Attrs.UnrollEnable != LoopAttributes::Unspecified) { 93 std::string Name; 94 if (Attrs.UnrollEnable == LoopAttributes::Enable) 95 Name = "llvm.loop.unroll.enable"; 96 else if (Attrs.UnrollEnable == LoopAttributes::Full) 97 Name = "llvm.loop.unroll.full"; 98 else 99 Name = "llvm.loop.unroll.disable"; 100 Metadata *Vals[] = {MDString::get(Ctx, Name)}; 101 Args.push_back(MDNode::get(Ctx, Vals)); 102 } 103 104 // Setting unroll_and_jam.full or unroll_and_jam.disable 105 if (Attrs.UnrollAndJamEnable != LoopAttributes::Unspecified) { 106 std::string Name; 107 if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable) 108 Name = "llvm.loop.unroll_and_jam.enable"; 109 else if (Attrs.UnrollAndJamEnable == LoopAttributes::Full) 110 Name = "llvm.loop.unroll_and_jam.full"; 111 else 112 Name = "llvm.loop.unroll_and_jam.disable"; 113 Metadata *Vals[] = {MDString::get(Ctx, Name)}; 114 Args.push_back(MDNode::get(Ctx, Vals)); 115 } 116 117 if (Attrs.DistributeEnable != LoopAttributes::Unspecified) { 118 Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"), 119 ConstantAsMetadata::get(ConstantInt::get( 120 Type::getInt1Ty(Ctx), (Attrs.DistributeEnable == 121 LoopAttributes::Enable)))}; 122 Args.push_back(MDNode::get(Ctx, Vals)); 123 } 124 125 if (Attrs.IsParallel) { 126 AccGroup = MDNode::getDistinct(Ctx, {}); 127 Args.push_back(MDNode::get( 128 Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup})); 129 } 130 131 if (Attrs.PipelineDisabled) { 132 Metadata *Vals[] = { 133 MDString::get(Ctx, "llvm.loop.pipeline.disable"), 134 ConstantAsMetadata::get(ConstantInt::get( 135 Type::getInt1Ty(Ctx), (Attrs.PipelineDisabled == true)))}; 136 Args.push_back(MDNode::get(Ctx, Vals)); 137 } 138 139 if (Attrs.PipelineInitiationInterval > 0) { 140 Metadata *Vals[] = { 141 MDString::get(Ctx, "llvm.loop.pipeline.initiationinterval"), 142 ConstantAsMetadata::get(ConstantInt::get( 143 Type::getInt32Ty(Ctx), Attrs.PipelineInitiationInterval))}; 144 Args.push_back(MDNode::get(Ctx, Vals)); 145 } 146 147 // Set the first operand to itself. 148 MDNode *LoopID = MDNode::get(Ctx, Args); 149 LoopID->replaceOperandWith(0, LoopID); 150 return LoopID; 151 } 152 153 LoopAttributes::LoopAttributes(bool IsParallel) 154 : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified), 155 UnrollEnable(LoopAttributes::Unspecified), 156 UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0), 157 InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0), 158 DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false), 159 PipelineInitiationInterval(0) {} 160 161 void LoopAttributes::clear() { 162 IsParallel = false; 163 VectorizeWidth = 0; 164 InterleaveCount = 0; 165 UnrollCount = 0; 166 UnrollAndJamCount = 0; 167 VectorizeEnable = LoopAttributes::Unspecified; 168 UnrollEnable = LoopAttributes::Unspecified; 169 UnrollAndJamEnable = LoopAttributes::Unspecified; 170 DistributeEnable = LoopAttributes::Unspecified; 171 PipelineDisabled = false; 172 PipelineInitiationInterval = 0; 173 } 174 175 LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs, 176 const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc) 177 : LoopID(nullptr), Header(Header), Attrs(Attrs) { 178 LoopID = 179 createMetadata(Header->getContext(), Attrs, StartLoc, EndLoc, AccGroup); 180 } 181 182 void LoopInfoStack::push(BasicBlock *Header, const llvm::DebugLoc &StartLoc, 183 const llvm::DebugLoc &EndLoc) { 184 Active.push_back(LoopInfo(Header, StagedAttrs, StartLoc, EndLoc)); 185 // Clear the attributes so nested loops do not inherit them. 186 StagedAttrs.clear(); 187 } 188 189 void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, 190 ArrayRef<const clang::Attr *> Attrs, 191 const llvm::DebugLoc &StartLoc, 192 const llvm::DebugLoc &EndLoc) { 193 194 // Identify loop hint attributes from Attrs. 195 for (const auto *Attr : Attrs) { 196 const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr); 197 const OpenCLUnrollHintAttr *OpenCLHint = 198 dyn_cast<OpenCLUnrollHintAttr>(Attr); 199 200 // Skip non loop hint attributes 201 if (!LH && !OpenCLHint) { 202 continue; 203 } 204 205 LoopHintAttr::OptionType Option = LoopHintAttr::Unroll; 206 LoopHintAttr::LoopHintState State = LoopHintAttr::Disable; 207 unsigned ValueInt = 1; 208 // Translate opencl_unroll_hint attribute argument to 209 // equivalent LoopHintAttr enums. 210 // OpenCL v2.0 s6.11.5: 211 // 0 - enable unroll (no argument). 212 // 1 - disable unroll. 213 // other positive integer n - unroll by n. 214 if (OpenCLHint) { 215 ValueInt = OpenCLHint->getUnrollHint(); 216 if (ValueInt == 0) { 217 State = LoopHintAttr::Enable; 218 } else if (ValueInt != 1) { 219 Option = LoopHintAttr::UnrollCount; 220 State = LoopHintAttr::Numeric; 221 } 222 } else if (LH) { 223 auto *ValueExpr = LH->getValue(); 224 if (ValueExpr) { 225 llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx); 226 ValueInt = ValueAPS.getSExtValue(); 227 } 228 229 Option = LH->getOption(); 230 State = LH->getState(); 231 } 232 switch (State) { 233 case LoopHintAttr::Disable: 234 switch (Option) { 235 case LoopHintAttr::Vectorize: 236 // Disable vectorization by specifying a width of 1. 237 setVectorizeWidth(1); 238 break; 239 case LoopHintAttr::Interleave: 240 // Disable interleaving by speciyfing a count of 1. 241 setInterleaveCount(1); 242 break; 243 case LoopHintAttr::Unroll: 244 setUnrollState(LoopAttributes::Disable); 245 break; 246 case LoopHintAttr::UnrollAndJam: 247 setUnrollAndJamState(LoopAttributes::Disable); 248 break; 249 case LoopHintAttr::Distribute: 250 setDistributeState(false); 251 break; 252 case LoopHintAttr::PipelineDisabled: 253 setPipelineDisabled(true); 254 break; 255 case LoopHintAttr::UnrollCount: 256 case LoopHintAttr::UnrollAndJamCount: 257 case LoopHintAttr::VectorizeWidth: 258 case LoopHintAttr::InterleaveCount: 259 case LoopHintAttr::PipelineInitiationInterval: 260 llvm_unreachable("Options cannot be disabled."); 261 break; 262 } 263 break; 264 case LoopHintAttr::Enable: 265 switch (Option) { 266 case LoopHintAttr::Vectorize: 267 case LoopHintAttr::Interleave: 268 setVectorizeEnable(true); 269 break; 270 case LoopHintAttr::Unroll: 271 setUnrollState(LoopAttributes::Enable); 272 break; 273 case LoopHintAttr::UnrollAndJam: 274 setUnrollAndJamState(LoopAttributes::Enable); 275 break; 276 case LoopHintAttr::Distribute: 277 setDistributeState(true); 278 break; 279 case LoopHintAttr::UnrollCount: 280 case LoopHintAttr::UnrollAndJamCount: 281 case LoopHintAttr::VectorizeWidth: 282 case LoopHintAttr::InterleaveCount: 283 case LoopHintAttr::PipelineDisabled: 284 case LoopHintAttr::PipelineInitiationInterval: 285 llvm_unreachable("Options cannot enabled."); 286 break; 287 } 288 break; 289 case LoopHintAttr::AssumeSafety: 290 switch (Option) { 291 case LoopHintAttr::Vectorize: 292 case LoopHintAttr::Interleave: 293 // Apply "llvm.mem.parallel_loop_access" metadata to load/stores. 294 setParallel(true); 295 setVectorizeEnable(true); 296 break; 297 case LoopHintAttr::Unroll: 298 case LoopHintAttr::UnrollAndJam: 299 case LoopHintAttr::UnrollCount: 300 case LoopHintAttr::UnrollAndJamCount: 301 case LoopHintAttr::VectorizeWidth: 302 case LoopHintAttr::InterleaveCount: 303 case LoopHintAttr::Distribute: 304 case LoopHintAttr::PipelineDisabled: 305 case LoopHintAttr::PipelineInitiationInterval: 306 llvm_unreachable("Options cannot be used to assume mem safety."); 307 break; 308 } 309 break; 310 case LoopHintAttr::Full: 311 switch (Option) { 312 case LoopHintAttr::Unroll: 313 setUnrollState(LoopAttributes::Full); 314 break; 315 case LoopHintAttr::UnrollAndJam: 316 setUnrollAndJamState(LoopAttributes::Full); 317 break; 318 case LoopHintAttr::Vectorize: 319 case LoopHintAttr::Interleave: 320 case LoopHintAttr::UnrollCount: 321 case LoopHintAttr::UnrollAndJamCount: 322 case LoopHintAttr::VectorizeWidth: 323 case LoopHintAttr::InterleaveCount: 324 case LoopHintAttr::Distribute: 325 case LoopHintAttr::PipelineDisabled: 326 case LoopHintAttr::PipelineInitiationInterval: 327 llvm_unreachable("Options cannot be used with 'full' hint."); 328 break; 329 } 330 break; 331 case LoopHintAttr::Numeric: 332 switch (Option) { 333 case LoopHintAttr::VectorizeWidth: 334 setVectorizeWidth(ValueInt); 335 break; 336 case LoopHintAttr::InterleaveCount: 337 setInterleaveCount(ValueInt); 338 break; 339 case LoopHintAttr::UnrollCount: 340 setUnrollCount(ValueInt); 341 break; 342 case LoopHintAttr::UnrollAndJamCount: 343 setUnrollAndJamCount(ValueInt); 344 break; 345 case LoopHintAttr::PipelineInitiationInterval: 346 setPipelineInitiationInterval(ValueInt); 347 break; 348 case LoopHintAttr::Unroll: 349 case LoopHintAttr::UnrollAndJam: 350 case LoopHintAttr::Vectorize: 351 case LoopHintAttr::Interleave: 352 case LoopHintAttr::Distribute: 353 case LoopHintAttr::PipelineDisabled: 354 llvm_unreachable("Options cannot be assigned a value."); 355 break; 356 } 357 break; 358 } 359 } 360 361 /// Stage the attributes. 362 push(Header, StartLoc, EndLoc); 363 } 364 365 void LoopInfoStack::pop() { 366 assert(!Active.empty() && "No active loops to pop"); 367 Active.pop_back(); 368 } 369 370 void LoopInfoStack::InsertHelper(Instruction *I) const { 371 if (I->mayReadOrWriteMemory()) { 372 SmallVector<Metadata *, 4> AccessGroups; 373 for (const LoopInfo &AL : Active) { 374 // Here we assume that every loop that has an access group is parallel. 375 if (MDNode *Group = AL.getAccessGroup()) 376 AccessGroups.push_back(Group); 377 } 378 MDNode *UnionMD = nullptr; 379 if (AccessGroups.size() == 1) 380 UnionMD = cast<MDNode>(AccessGroups[0]); 381 else if (AccessGroups.size() >= 2) 382 UnionMD = MDNode::get(I->getContext(), AccessGroups); 383 I->setMetadata("llvm.access.group", UnionMD); 384 } 385 386 if (!hasInfo()) 387 return; 388 389 const LoopInfo &L = getInfo(); 390 if (!L.getLoopID()) 391 return; 392 393 if (I->isTerminator()) { 394 for (BasicBlock *Succ : successors(I)) 395 if (Succ == L.getHeader()) { 396 I->setMetadata(llvm::LLVMContext::MD_loop, L.getLoopID()); 397 break; 398 } 399 return; 400 } 401 } 402