1 //===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "CGLoopInfo.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Attr.h"
13 #include "clang/Sema/LoopHint.h"
14 #include "llvm/IR/BasicBlock.h"
15 #include "llvm/IR/Constants.h"
16 #include "llvm/IR/InstrTypes.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/Metadata.h"
19 using namespace clang::CodeGen;
20 using namespace llvm;
21 
22 static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs,
23                               llvm::DebugLoc StartLoc, llvm::DebugLoc EndLoc) {
24 
25   if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
26       Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
27       Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
28       Attrs.UnrollEnable == LoopAttributes::Unspecified &&
29       Attrs.DistributeEnable == LoopAttributes::Unspecified &&
30       !StartLoc && !EndLoc)
31     return nullptr;
32 
33   SmallVector<Metadata *, 4> Args;
34   // Reserve operand 0 for loop id self reference.
35   auto TempNode = MDNode::getTemporary(Ctx, None);
36   Args.push_back(TempNode.get());
37 
38   // If we have a valid start debug location for the loop, add it.
39   if (StartLoc) {
40     Args.push_back(StartLoc.getAsMDNode());
41 
42     // If we also have a valid end debug location for the loop, add it.
43     if (EndLoc)
44       Args.push_back(EndLoc.getAsMDNode());
45   }
46 
47   // Setting vectorize.width
48   if (Attrs.VectorizeWidth > 0) {
49     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.width"),
50                         ConstantAsMetadata::get(ConstantInt::get(
51                             Type::getInt32Ty(Ctx), Attrs.VectorizeWidth))};
52     Args.push_back(MDNode::get(Ctx, Vals));
53   }
54 
55   // Setting interleave.count
56   if (Attrs.InterleaveCount > 0) {
57     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.interleave.count"),
58                         ConstantAsMetadata::get(ConstantInt::get(
59                             Type::getInt32Ty(Ctx), Attrs.InterleaveCount))};
60     Args.push_back(MDNode::get(Ctx, Vals));
61   }
62 
63   // Setting interleave.count
64   if (Attrs.UnrollCount > 0) {
65     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"),
66                         ConstantAsMetadata::get(ConstantInt::get(
67                             Type::getInt32Ty(Ctx), Attrs.UnrollCount))};
68     Args.push_back(MDNode::get(Ctx, Vals));
69   }
70 
71   // Setting vectorize.enable
72   if (Attrs.VectorizeEnable != LoopAttributes::Unspecified) {
73     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
74                         ConstantAsMetadata::get(ConstantInt::get(
75                             Type::getInt1Ty(Ctx), (Attrs.VectorizeEnable ==
76                                                    LoopAttributes::Enable)))};
77     Args.push_back(MDNode::get(Ctx, Vals));
78   }
79 
80   // Setting unroll.full or unroll.disable
81   if (Attrs.UnrollEnable != LoopAttributes::Unspecified) {
82     std::string Name;
83     if (Attrs.UnrollEnable == LoopAttributes::Enable)
84       Name = "llvm.loop.unroll.enable";
85     else if (Attrs.UnrollEnable == LoopAttributes::Full)
86       Name = "llvm.loop.unroll.full";
87     else
88       Name = "llvm.loop.unroll.disable";
89     Metadata *Vals[] = {MDString::get(Ctx, Name)};
90     Args.push_back(MDNode::get(Ctx, Vals));
91   }
92 
93   if (Attrs.DistributeEnable != LoopAttributes::Unspecified) {
94     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"),
95                         ConstantAsMetadata::get(ConstantInt::get(
96                             Type::getInt1Ty(Ctx), (Attrs.DistributeEnable ==
97                                                    LoopAttributes::Enable)))};
98     Args.push_back(MDNode::get(Ctx, Vals));
99   }
100 
101   // Set the first operand to itself.
102   MDNode *LoopID = MDNode::get(Ctx, Args);
103   LoopID->replaceOperandWith(0, LoopID);
104   return LoopID;
105 }
106 
107 LoopAttributes::LoopAttributes(bool IsParallel)
108     : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
109       UnrollEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
110       InterleaveCount(0), UnrollCount(0),
111       DistributeEnable(LoopAttributes::Unspecified) {}
112 
113 void LoopAttributes::clear() {
114   IsParallel = false;
115   VectorizeWidth = 0;
116   InterleaveCount = 0;
117   UnrollCount = 0;
118   VectorizeEnable = LoopAttributes::Unspecified;
119   UnrollEnable = LoopAttributes::Unspecified;
120   DistributeEnable = LoopAttributes::Unspecified;
121 }
122 
123 LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
124                    llvm::DebugLoc StartLoc, llvm::DebugLoc EndLoc)
125     : LoopID(nullptr), Header(Header), Attrs(Attrs) {
126   LoopID = createMetadata(Header->getContext(), Attrs, StartLoc, EndLoc);
127 }
128 
129 void LoopInfoStack::push(BasicBlock *Header, llvm::DebugLoc StartLoc,
130                          llvm::DebugLoc EndLoc) {
131   Active.push_back(LoopInfo(Header, StagedAttrs, StartLoc, EndLoc));
132   // Clear the attributes so nested loops do not inherit them.
133   StagedAttrs.clear();
134 }
135 
136 void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
137                          ArrayRef<const clang::Attr *> Attrs,
138                          llvm::DebugLoc StartLoc, llvm::DebugLoc EndLoc) {
139 
140   // Identify loop hint attributes from Attrs.
141   for (const auto *Attr : Attrs) {
142     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
143     const OpenCLUnrollHintAttr *OpenCLHint =
144         dyn_cast<OpenCLUnrollHintAttr>(Attr);
145 
146     // Skip non loop hint attributes
147     if (!LH && !OpenCLHint) {
148       continue;
149     }
150 
151     LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
152     LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
153     unsigned ValueInt = 1;
154     // Translate opencl_unroll_hint attribute argument to
155     // equivalent LoopHintAttr enums.
156     // OpenCL v2.0 s6.11.5:
157     // 0 - full unroll (no argument).
158     // 1 - disable unroll.
159     // other positive integer n - unroll by n.
160     if (OpenCLHint) {
161       ValueInt = OpenCLHint->getUnrollHint();
162       if (ValueInt == 0) {
163         State = LoopHintAttr::Full;
164       } else if (ValueInt != 1) {
165         Option = LoopHintAttr::UnrollCount;
166         State = LoopHintAttr::Numeric;
167       }
168     } else if (LH) {
169       auto *ValueExpr = LH->getValue();
170       if (ValueExpr) {
171         llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
172         ValueInt = ValueAPS.getSExtValue();
173       }
174 
175       Option = LH->getOption();
176       State = LH->getState();
177     }
178     switch (State) {
179     case LoopHintAttr::Disable:
180       switch (Option) {
181       case LoopHintAttr::Vectorize:
182         // Disable vectorization by specifying a width of 1.
183         setVectorizeWidth(1);
184         break;
185       case LoopHintAttr::Interleave:
186         // Disable interleaving by speciyfing a count of 1.
187         setInterleaveCount(1);
188         break;
189       case LoopHintAttr::Unroll:
190         setUnrollState(LoopAttributes::Disable);
191         break;
192       case LoopHintAttr::Distribute:
193         setDistributeState(false);
194         break;
195       case LoopHintAttr::UnrollCount:
196       case LoopHintAttr::VectorizeWidth:
197       case LoopHintAttr::InterleaveCount:
198         llvm_unreachable("Options cannot be disabled.");
199         break;
200       }
201       break;
202     case LoopHintAttr::Enable:
203       switch (Option) {
204       case LoopHintAttr::Vectorize:
205       case LoopHintAttr::Interleave:
206         setVectorizeEnable(true);
207         break;
208       case LoopHintAttr::Unroll:
209         setUnrollState(LoopAttributes::Enable);
210         break;
211       case LoopHintAttr::Distribute:
212         setDistributeState(true);
213         break;
214       case LoopHintAttr::UnrollCount:
215       case LoopHintAttr::VectorizeWidth:
216       case LoopHintAttr::InterleaveCount:
217         llvm_unreachable("Options cannot enabled.");
218         break;
219       }
220       break;
221     case LoopHintAttr::AssumeSafety:
222       switch (Option) {
223       case LoopHintAttr::Vectorize:
224       case LoopHintAttr::Interleave:
225         // Apply "llvm.mem.parallel_loop_access" metadata to load/stores.
226         setParallel(true);
227         setVectorizeEnable(true);
228         break;
229       case LoopHintAttr::Unroll:
230       case LoopHintAttr::UnrollCount:
231       case LoopHintAttr::VectorizeWidth:
232       case LoopHintAttr::InterleaveCount:
233       case LoopHintAttr::Distribute:
234         llvm_unreachable("Options cannot be used to assume mem safety.");
235         break;
236       }
237       break;
238     case LoopHintAttr::Full:
239       switch (Option) {
240       case LoopHintAttr::Unroll:
241         setUnrollState(LoopAttributes::Full);
242         break;
243       case LoopHintAttr::Vectorize:
244       case LoopHintAttr::Interleave:
245       case LoopHintAttr::UnrollCount:
246       case LoopHintAttr::VectorizeWidth:
247       case LoopHintAttr::InterleaveCount:
248       case LoopHintAttr::Distribute:
249         llvm_unreachable("Options cannot be used with 'full' hint.");
250         break;
251       }
252       break;
253     case LoopHintAttr::Numeric:
254       switch (Option) {
255       case LoopHintAttr::VectorizeWidth:
256         setVectorizeWidth(ValueInt);
257         break;
258       case LoopHintAttr::InterleaveCount:
259         setInterleaveCount(ValueInt);
260         break;
261       case LoopHintAttr::UnrollCount:
262         setUnrollCount(ValueInt);
263         break;
264       case LoopHintAttr::Unroll:
265       case LoopHintAttr::Vectorize:
266       case LoopHintAttr::Interleave:
267       case LoopHintAttr::Distribute:
268         llvm_unreachable("Options cannot be assigned a value.");
269         break;
270       }
271       break;
272     }
273   }
274 
275   /// Stage the attributes.
276   push(Header, StartLoc, EndLoc);
277 }
278 
279 void LoopInfoStack::pop() {
280   assert(!Active.empty() && "No active loops to pop");
281   Active.pop_back();
282 }
283 
284 void LoopInfoStack::InsertHelper(Instruction *I) const {
285   if (!hasInfo())
286     return;
287 
288   const LoopInfo &L = getInfo();
289   if (!L.getLoopID())
290     return;
291 
292   if (TerminatorInst *TI = dyn_cast<TerminatorInst>(I)) {
293     for (unsigned i = 0, ie = TI->getNumSuccessors(); i < ie; ++i)
294       if (TI->getSuccessor(i) == L.getHeader()) {
295         TI->setMetadata(llvm::LLVMContext::MD_loop, L.getLoopID());
296         break;
297       }
298     return;
299   }
300 
301   if (L.getAttributes().IsParallel && I->mayReadOrWriteMemory())
302     I->setMetadata("llvm.mem.parallel_loop_access", L.getLoopID());
303 }
304