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