1//===--- LoopAttributes.cpp - Shared loop hint state ----------------------===//
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 "clang/CodeGenUtils/LoopAttributes.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/AST/Attr.h"
12#include "clang/AST/Expr.h"
13#include "clang/Basic/CodeGenOptions.h"
14#include "llvm/Support/ErrorHandling.h"
15
16namespace clang::CodeGenUtils {
17
18LoopAttributes::LoopAttributes(bool IsParallel)
19 : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
20 UnrollEnable(LoopAttributes::Unspecified),
21 UnrollAndJamEnable(LoopAttributes::Unspecified),
22 VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
23 VectorizeScalable(LoopAttributes::Unspecified), InterleaveCount(0),
24 UnrollCount(0), UnrollAndJamCount(0),
25 DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
26 LICMDisabled(false), PipelineInitiationInterval(0), CodeAlign(0),
27 MustProgress(false) {}
28
29void LoopAttributes::clear() {
30 IsParallel = false;
31 VectorizeWidth = 0;
32 VectorizeScalable = LoopAttributes::Unspecified;
33 InterleaveCount = 0;
34 UnrollCount = 0;
35 UnrollAndJamCount = 0;
36 VectorizeEnable = LoopAttributes::Unspecified;
37 UnrollEnable = LoopAttributes::Unspecified;
38 UnrollAndJamEnable = LoopAttributes::Unspecified;
39 VectorizePredicateEnable = LoopAttributes::Unspecified;
40 DistributeEnable = LoopAttributes::Unspecified;
41 PipelineDisabled = false;
42 LICMDisabled = false;
43 PipelineInitiationInterval = 0;
44 CodeAlign = 0;
45 MustProgress = false;
46}
47
48void updateLoopAttributes(LoopAttributes &Attrs, ASTContext &Ctx,
49 const CodeGenOptions &CGOpts,
50 llvm::ArrayRef<const Attr *> StmtAttrs,
51 bool MustProgress) {
52 // Identify loop hint attributes from Attrs.
53 for (const auto *Attr : StmtAttrs) {
54 const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Val: Attr);
55 const OpenCLUnrollHintAttr *OpenCLHint =
56 dyn_cast<OpenCLUnrollHintAttr>(Val: Attr);
57 const HLSLLoopHintAttr *HLSLLoopHint = dyn_cast<HLSLLoopHintAttr>(Val: Attr);
58 // Skip non loop hint attributes
59 if (!LH && !OpenCLHint && !HLSLLoopHint) {
60 continue;
61 }
62
63 LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
64 LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
65 unsigned ValueInt = 1;
66 // Translate opencl_unroll_hint attribute argument to
67 // equivalent LoopHintAttr enums.
68 // OpenCL v2.0 s6.11.5:
69 // 0 - enable unroll (no argument).
70 // 1 - disable unroll.
71 // other positive integer n - unroll by n.
72 if (OpenCLHint) {
73 ValueInt = OpenCLHint->getUnrollHint();
74 if (ValueInt == 0) {
75 State = LoopHintAttr::Enable;
76 } else if (ValueInt != 1) {
77 Option = LoopHintAttr::UnrollCount;
78 State = LoopHintAttr::Numeric;
79 }
80 } else if (HLSLLoopHint) {
81 ValueInt = HLSLLoopHint->getDirective();
82 if (HLSLLoopHint->getSemanticSpelling() ==
83 HLSLLoopHintAttr::Spelling::Microsoft_unroll) {
84 if (ValueInt == 0)
85 State = LoopHintAttr::Enable;
86 if (ValueInt > 0) {
87 Option = LoopHintAttr::UnrollCount;
88 State = LoopHintAttr::Numeric;
89 }
90 }
91 } else if (LH) {
92 auto *ValueExpr = LH->getValue();
93 if (ValueExpr) {
94 llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
95 ValueInt = ValueAPS.getSExtValue();
96 }
97
98 Option = LH->getOption();
99 State = LH->getState();
100 }
101 switch (State) {
102 case LoopHintAttr::Disable:
103 switch (Option) {
104 case LoopHintAttr::Vectorize:
105 // Disable vectorization by specifying a width of 1 and disabling
106 // scalable vectorization explicitly.
107 Attrs.VectorizeWidth = 1;
108 Attrs.VectorizeScalable = LoopAttributes::Disable;
109 break;
110 case LoopHintAttr::Interleave:
111 // Disable interleaving by speciyfing a count of 1.
112 Attrs.InterleaveCount = 1;
113 break;
114 case LoopHintAttr::Unroll:
115 Attrs.UnrollEnable = LoopAttributes::Disable;
116 break;
117 case LoopHintAttr::UnrollAndJam:
118 Attrs.UnrollAndJamEnable = LoopAttributes::Disable;
119 break;
120 case LoopHintAttr::VectorizePredicate:
121 Attrs.VectorizePredicateEnable = LoopAttributes::Disable;
122 break;
123 case LoopHintAttr::Distribute:
124 Attrs.DistributeEnable = LoopAttributes::Disable;
125 break;
126 case LoopHintAttr::PipelineDisabled:
127 Attrs.PipelineDisabled = true;
128 break;
129 case LoopHintAttr::LICMDisabled:
130 Attrs.LICMDisabled = true;
131 break;
132 case LoopHintAttr::UnrollCount:
133 case LoopHintAttr::UnrollAndJamCount:
134 case LoopHintAttr::VectorizeWidth:
135 case LoopHintAttr::InterleaveCount:
136 case LoopHintAttr::PipelineInitiationInterval:
137 llvm_unreachable("Options cannot be disabled.");
138 break;
139 }
140 break;
141 case LoopHintAttr::Enable:
142 switch (Option) {
143 case LoopHintAttr::Vectorize:
144 case LoopHintAttr::Interleave:
145 Attrs.VectorizeEnable = LoopAttributes::Enable;
146 break;
147 case LoopHintAttr::Unroll:
148 Attrs.UnrollEnable = LoopAttributes::Enable;
149 break;
150 case LoopHintAttr::UnrollAndJam:
151 Attrs.UnrollAndJamEnable = LoopAttributes::Enable;
152 break;
153 case LoopHintAttr::VectorizePredicate:
154 Attrs.VectorizePredicateEnable = LoopAttributes::Enable;
155 break;
156 case LoopHintAttr::Distribute:
157 Attrs.DistributeEnable = LoopAttributes::Enable;
158 break;
159 case LoopHintAttr::UnrollCount:
160 case LoopHintAttr::UnrollAndJamCount:
161 case LoopHintAttr::VectorizeWidth:
162 case LoopHintAttr::InterleaveCount:
163 case LoopHintAttr::PipelineDisabled:
164 case LoopHintAttr::PipelineInitiationInterval:
165 case LoopHintAttr::LICMDisabled:
166 llvm_unreachable("Options cannot enabled.");
167 break;
168 }
169 break;
170 case LoopHintAttr::AssumeSafety:
171 switch (Option) {
172 case LoopHintAttr::Vectorize:
173 case LoopHintAttr::Interleave:
174 // Apply "llvm.mem.parallel_loop_access" metadata to load/stores.
175 Attrs.IsParallel = true;
176 Attrs.VectorizeEnable = LoopAttributes::Enable;
177 break;
178 case LoopHintAttr::Unroll:
179 case LoopHintAttr::UnrollAndJam:
180 case LoopHintAttr::VectorizePredicate:
181 case LoopHintAttr::UnrollCount:
182 case LoopHintAttr::UnrollAndJamCount:
183 case LoopHintAttr::VectorizeWidth:
184 case LoopHintAttr::InterleaveCount:
185 case LoopHintAttr::Distribute:
186 case LoopHintAttr::PipelineDisabled:
187 case LoopHintAttr::PipelineInitiationInterval:
188 case LoopHintAttr::LICMDisabled:
189 llvm_unreachable("Options cannot be used to assume mem safety.");
190 break;
191 }
192 break;
193 case LoopHintAttr::Full:
194 switch (Option) {
195 case LoopHintAttr::Unroll:
196 Attrs.UnrollEnable = LoopAttributes::Full;
197 break;
198 case LoopHintAttr::UnrollAndJam:
199 Attrs.UnrollAndJamEnable = LoopAttributes::Full;
200 break;
201 case LoopHintAttr::Vectorize:
202 case LoopHintAttr::Interleave:
203 case LoopHintAttr::UnrollCount:
204 case LoopHintAttr::UnrollAndJamCount:
205 case LoopHintAttr::VectorizeWidth:
206 case LoopHintAttr::InterleaveCount:
207 case LoopHintAttr::Distribute:
208 case LoopHintAttr::PipelineDisabled:
209 case LoopHintAttr::PipelineInitiationInterval:
210 case LoopHintAttr::VectorizePredicate:
211 case LoopHintAttr::LICMDisabled:
212 llvm_unreachable("Options cannot be used with 'full' hint.");
213 break;
214 }
215 break;
216 case LoopHintAttr::FixedWidth:
217 case LoopHintAttr::ScalableWidth:
218 switch (Option) {
219 case LoopHintAttr::VectorizeWidth:
220 Attrs.VectorizeScalable = State == LoopHintAttr::ScalableWidth
221 ? LoopAttributes::Enable
222 : LoopAttributes::Disable;
223 if (LH->getValue())
224 Attrs.VectorizeWidth = ValueInt;
225 break;
226 default:
227 llvm_unreachable("Options cannot be used with 'scalable' hint.");
228 break;
229 }
230 break;
231 case LoopHintAttr::Numeric:
232 switch (Option) {
233 case LoopHintAttr::InterleaveCount:
234 Attrs.InterleaveCount = ValueInt;
235 break;
236 case LoopHintAttr::UnrollCount:
237 Attrs.UnrollCount = ValueInt;
238 break;
239 case LoopHintAttr::UnrollAndJamCount:
240 Attrs.UnrollAndJamCount = ValueInt;
241 break;
242 case LoopHintAttr::PipelineInitiationInterval:
243 Attrs.PipelineInitiationInterval = ValueInt;
244 break;
245 case LoopHintAttr::Unroll:
246 case LoopHintAttr::UnrollAndJam:
247 case LoopHintAttr::VectorizePredicate:
248 case LoopHintAttr::Vectorize:
249 case LoopHintAttr::VectorizeWidth:
250 case LoopHintAttr::Interleave:
251 case LoopHintAttr::Distribute:
252 case LoopHintAttr::PipelineDisabled:
253 case LoopHintAttr::LICMDisabled:
254 llvm_unreachable("Options cannot be assigned a value.");
255 break;
256 }
257 break;
258 }
259 }
260
261 // Identify loop attribute 'code_align' from Attrs.
262 // For attribute code_align:
263 // n - 'llvm.loop.align i32 n' metadata will be emitted.
264 // A source-level [[clang::code_align]] attribute takes precedence over the
265 // -falign-loops=N command-line default.
266 if (const auto *CodeAlign = getSpecificAttr<CodeAlignAttr>(container: StmtAttrs)) {
267 const auto *CE = cast<ConstantExpr>(Val: CodeAlign->getAlignment());
268 llvm::APSInt ArgVal = CE->getResultAsAPSInt();
269 Attrs.CodeAlign = ArgVal.getSExtValue();
270 } else if (CGOpts.LoopAlignment) {
271 Attrs.CodeAlign = CGOpts.LoopAlignment;
272 }
273
274 Attrs.MustProgress = MustProgress;
275
276 if (CGOpts.OptimizationLevel > 0)
277 // Disable unrolling for the loop, if unrolling is disabled (via
278 // -fno-unroll-loops) and no pragmas override the decision.
279 if (!CGOpts.UnrollLoops &&
280 (Attrs.UnrollEnable == LoopAttributes::Unspecified &&
281 Attrs.UnrollCount == 0))
282 Attrs.UnrollEnable = LoopAttributes::Disable;
283}
284
285} // namespace clang::CodeGenUtils
286