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                               const llvm::DebugLoc &StartLoc,
24                               const llvm::DebugLoc &EndLoc) {
25 
26   if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
27       Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
28       Attrs.UnrollAndJamCount == 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   // Set the first operand to itself.
126   MDNode *LoopID = MDNode::get(Ctx, Args);
127   LoopID->replaceOperandWith(0, LoopID);
128   return LoopID;
129 }
130 
131 LoopAttributes::LoopAttributes(bool IsParallel)
132     : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
133       UnrollEnable(LoopAttributes::Unspecified),
134       UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
135       InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
136       DistributeEnable(LoopAttributes::Unspecified) {}
137 
138 void LoopAttributes::clear() {
139   IsParallel = false;
140   VectorizeWidth = 0;
141   InterleaveCount = 0;
142   UnrollCount = 0;
143   UnrollAndJamCount = 0;
144   VectorizeEnable = LoopAttributes::Unspecified;
145   UnrollEnable = LoopAttributes::Unspecified;
146   UnrollAndJamEnable = LoopAttributes::Unspecified;
147   DistributeEnable = LoopAttributes::Unspecified;
148 }
149 
150 LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
151                    const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc)
152     : LoopID(nullptr), Header(Header), Attrs(Attrs) {
153   LoopID = createMetadata(Header->getContext(), Attrs, StartLoc, EndLoc);
154 }
155 
156 void LoopInfoStack::push(BasicBlock *Header, const llvm::DebugLoc &StartLoc,
157                          const llvm::DebugLoc &EndLoc) {
158   Active.push_back(LoopInfo(Header, StagedAttrs, StartLoc, EndLoc));
159   // Clear the attributes so nested loops do not inherit them.
160   StagedAttrs.clear();
161 }
162 
163 void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
164                          ArrayRef<const clang::Attr *> Attrs,
165                          const llvm::DebugLoc &StartLoc,
166                          const llvm::DebugLoc &EndLoc) {
167 
168   // Identify loop hint attributes from Attrs.
169   for (const auto *Attr : Attrs) {
170     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
171     const OpenCLUnrollHintAttr *OpenCLHint =
172         dyn_cast<OpenCLUnrollHintAttr>(Attr);
173 
174     // Skip non loop hint attributes
175     if (!LH && !OpenCLHint) {
176       continue;
177     }
178 
179     LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
180     LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
181     unsigned ValueInt = 1;
182     // Translate opencl_unroll_hint attribute argument to
183     // equivalent LoopHintAttr enums.
184     // OpenCL v2.0 s6.11.5:
185     // 0 - full unroll (no argument).
186     // 1 - disable unroll.
187     // other positive integer n - unroll by n.
188     if (OpenCLHint) {
189       ValueInt = OpenCLHint->getUnrollHint();
190       if (ValueInt == 0) {
191         State = LoopHintAttr::Full;
192       } else if (ValueInt != 1) {
193         Option = LoopHintAttr::UnrollCount;
194         State = LoopHintAttr::Numeric;
195       }
196     } else if (LH) {
197       auto *ValueExpr = LH->getValue();
198       if (ValueExpr) {
199         llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
200         ValueInt = ValueAPS.getSExtValue();
201       }
202 
203       Option = LH->getOption();
204       State = LH->getState();
205     }
206     switch (State) {
207     case LoopHintAttr::Disable:
208       switch (Option) {
209       case LoopHintAttr::Vectorize:
210         // Disable vectorization by specifying a width of 1.
211         setVectorizeWidth(1);
212         break;
213       case LoopHintAttr::Interleave:
214         // Disable interleaving by speciyfing a count of 1.
215         setInterleaveCount(1);
216         break;
217       case LoopHintAttr::Unroll:
218         setUnrollState(LoopAttributes::Disable);
219         break;
220       case LoopHintAttr::UnrollAndJam:
221         setUnrollAndJamState(LoopAttributes::Disable);
222         break;
223       case LoopHintAttr::Distribute:
224         setDistributeState(false);
225         break;
226       case LoopHintAttr::UnrollCount:
227       case LoopHintAttr::UnrollAndJamCount:
228       case LoopHintAttr::VectorizeWidth:
229       case LoopHintAttr::InterleaveCount:
230         llvm_unreachable("Options cannot be disabled.");
231         break;
232       }
233       break;
234     case LoopHintAttr::Enable:
235       switch (Option) {
236       case LoopHintAttr::Vectorize:
237       case LoopHintAttr::Interleave:
238         setVectorizeEnable(true);
239         break;
240       case LoopHintAttr::Unroll:
241         setUnrollState(LoopAttributes::Enable);
242         break;
243       case LoopHintAttr::UnrollAndJam:
244         setUnrollAndJamState(LoopAttributes::Enable);
245         break;
246       case LoopHintAttr::Distribute:
247         setDistributeState(true);
248         break;
249       case LoopHintAttr::UnrollCount:
250       case LoopHintAttr::UnrollAndJamCount:
251       case LoopHintAttr::VectorizeWidth:
252       case LoopHintAttr::InterleaveCount:
253         llvm_unreachable("Options cannot enabled.");
254         break;
255       }
256       break;
257     case LoopHintAttr::AssumeSafety:
258       switch (Option) {
259       case LoopHintAttr::Vectorize:
260       case LoopHintAttr::Interleave:
261         // Apply "llvm.mem.parallel_loop_access" metadata to load/stores.
262         setParallel(true);
263         setVectorizeEnable(true);
264         break;
265       case LoopHintAttr::Unroll:
266       case LoopHintAttr::UnrollAndJam:
267       case LoopHintAttr::UnrollCount:
268       case LoopHintAttr::UnrollAndJamCount:
269       case LoopHintAttr::VectorizeWidth:
270       case LoopHintAttr::InterleaveCount:
271       case LoopHintAttr::Distribute:
272         llvm_unreachable("Options cannot be used to assume mem safety.");
273         break;
274       }
275       break;
276     case LoopHintAttr::Full:
277       switch (Option) {
278       case LoopHintAttr::Unroll:
279         setUnrollState(LoopAttributes::Full);
280         break;
281       case LoopHintAttr::UnrollAndJam:
282         setUnrollAndJamState(LoopAttributes::Full);
283         break;
284       case LoopHintAttr::Vectorize:
285       case LoopHintAttr::Interleave:
286       case LoopHintAttr::UnrollCount:
287       case LoopHintAttr::UnrollAndJamCount:
288       case LoopHintAttr::VectorizeWidth:
289       case LoopHintAttr::InterleaveCount:
290       case LoopHintAttr::Distribute:
291         llvm_unreachable("Options cannot be used with 'full' hint.");
292         break;
293       }
294       break;
295     case LoopHintAttr::Numeric:
296       switch (Option) {
297       case LoopHintAttr::VectorizeWidth:
298         setVectorizeWidth(ValueInt);
299         break;
300       case LoopHintAttr::InterleaveCount:
301         setInterleaveCount(ValueInt);
302         break;
303       case LoopHintAttr::UnrollCount:
304         setUnrollCount(ValueInt);
305         break;
306       case LoopHintAttr::UnrollAndJamCount:
307         setUnrollAndJamCount(ValueInt);
308         break;
309       case LoopHintAttr::Unroll:
310       case LoopHintAttr::UnrollAndJam:
311       case LoopHintAttr::Vectorize:
312       case LoopHintAttr::Interleave:
313       case LoopHintAttr::Distribute:
314         llvm_unreachable("Options cannot be assigned a value.");
315         break;
316       }
317       break;
318     }
319   }
320 
321   /// Stage the attributes.
322   push(Header, StartLoc, EndLoc);
323 }
324 
325 void LoopInfoStack::pop() {
326   assert(!Active.empty() && "No active loops to pop");
327   Active.pop_back();
328 }
329 
330 void LoopInfoStack::InsertHelper(Instruction *I) const {
331   if (!hasInfo())
332     return;
333 
334   const LoopInfo &L = getInfo();
335   if (!L.getLoopID())
336     return;
337 
338   if (TerminatorInst *TI = dyn_cast<TerminatorInst>(I)) {
339     for (unsigned i = 0, ie = TI->getNumSuccessors(); i < ie; ++i)
340       if (TI->getSuccessor(i) == L.getHeader()) {
341         TI->setMetadata(llvm::LLVMContext::MD_loop, L.getLoopID());
342         break;
343       }
344     return;
345   }
346 
347   if (I->mayReadOrWriteMemory()) {
348     SmallVector<Metadata *, 2> ParallelLoopIDs;
349     for (const LoopInfo &AL : Active)
350       if (AL.getAttributes().IsParallel)
351         ParallelLoopIDs.push_back(AL.getLoopID());
352 
353     MDNode *ParallelMD = nullptr;
354     if (ParallelLoopIDs.size() == 1)
355       ParallelMD = cast<MDNode>(ParallelLoopIDs[0]);
356     else if (ParallelLoopIDs.size() >= 2)
357       ParallelMD = MDNode::get(I->getContext(), ParallelLoopIDs);
358     I->setMetadata("llvm.mem.parallel_loop_access", ParallelMD);
359   }
360 }
361