blob: 846209964b57e7864d7d480e463b915b04107773 [file] [log] [blame]
Stephen Hines5baf6322011-04-25 17:21:15 -07001/*
Stephen Hines9999ec32012-02-10 18:22:14 -08002 * Copyright 2011-2012, The Android Open Source Project
Stephen Hines5baf6322011-04-25 17:21:15 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Stephen Hines593a8942011-05-10 15:29:50 -070017#include "slang_rs_export_foreach.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070018
19#include <string>
20
21#include "clang/AST/ASTContext.h"
22#include "clang/AST/Decl.h"
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070023#include "clang/AST/TypeLoc.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070024
25#include "llvm/DerivedTypes.h"
26#include "llvm/Target/TargetData.h"
27
28#include "slang_assert.h"
29#include "slang_rs_context.h"
Stephen Hines593a8942011-05-10 15:29:50 -070030#include "slang_rs_export_type.h"
Stephen Hines12580dc2011-10-10 17:44:10 -070031#include "slang_version.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070032
33namespace slang {
34
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070035namespace {
36
Logan Chien9207a2e2011-10-21 15:39:28 +080037static void ReportNameError(clang::DiagnosticsEngine *DiagEngine,
38 clang::ParmVarDecl const *PVD) {
39 slangAssert(DiagEngine && PVD);
40 const clang::SourceManager &SM = DiagEngine->getSourceManager();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070041
Logan Chien9207a2e2011-10-21 15:39:28 +080042 DiagEngine->Report(
43 clang::FullSourceLoc(PVD->getLocation(), SM),
44 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
45 "Duplicate parameter entry "
46 "(by position/name): '%0'"))
47 << PVD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070048 return;
49}
50
51} // namespace
52
Stephen Hines9ca96e72012-09-13 16:57:06 -070053
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070054// This function takes care of additional validation and construction of
55// parameters related to forEach_* reflection.
56bool RSExportForEach::validateAndConstructParams(
57 RSContext *Context, const clang::FunctionDecl *FD) {
58 slangAssert(Context && FD);
59 bool valid = true;
60 clang::ASTContext &C = Context->getASTContext();
Logan Chien9207a2e2011-10-21 15:39:28 +080061 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070062
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070063 numParams = FD->getNumParams();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070064
Stephen Hines7b51b552012-02-16 00:12:38 -080065 if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
66 if (!isRootRSFunc(FD)) {
67 DiagEngine->Report(
68 clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()),
69 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
70 "Non-root compute kernel %0() is "
71 "not supported in SDK levels %1-%2"))
72 << FD->getName()
73 << SLANG_MINIMUM_TARGET_API
74 << (SLANG_JB_TARGET_API - 1);
75 return false;
76 }
77 }
78
Stephen Hines9ca96e72012-09-13 16:57:06 -070079 mResultType = FD->getResultType().getCanonicalType();
80 // Compute kernel functions are required to return a void type or
81 // be marked explicitly as a kernel. In the case of
82 // "__attribute__((kernel))", we handle validation differently.
83 if (FD->hasAttr<clang::KernelAttr>()) {
84 return validateAndConstructKernelParams(Context, FD);
85 }
86
87 // If numParams is 0, we already marked this as a graphics root().
88 slangAssert(numParams > 0);
89
90 // Compute kernel functions of this type are required to return a void type.
91 if (mResultType != C.VoidTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +080092 DiagEngine->Report(
93 clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()),
94 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines7b51b552012-02-16 00:12:38 -080095 "Compute kernel %0() is required to return a "
96 "void type")) << FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070097 valid = false;
98 }
99
100 // Validate remaining parameter types
101 // TODO(all): Add support for LOD/face when we have them
102
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700103 size_t i = 0;
104 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
105 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700106
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700107 // Check for const T1 *in
108 if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) {
109 mIn = PVD;
110 i++; // advance parameter pointer
111 }
112
113 // Check for T2 *out
114 if (i < numParams) {
115 PVD = FD->getParamDecl(i);
116 QT = PVD->getType().getCanonicalType();
117 if (QT->isPointerType() && !QT->getPointeeType().isConstQualified()) {
118 mOut = PVD;
119 i++; // advance parameter pointer
120 }
121 }
122
123 if (!mIn && !mOut) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800124 DiagEngine->Report(
125 clang::FullSourceLoc(FD->getLocation(),
126 DiagEngine->getSourceManager()),
127 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines7b51b552012-02-16 00:12:38 -0800128 "Compute kernel %0() must have at least one "
129 "parameter for in or out")) << FD->getName();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700130 valid = false;
131 }
132
133 // Check for T3 *usrData
134 if (i < numParams) {
135 PVD = FD->getParamDecl(i);
136 QT = PVD->getType().getCanonicalType();
137 if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) {
138 mUsrData = PVD;
139 i++; // advance parameter pointer
140 }
141 }
142
143 while (i < numParams) {
144 PVD = FD->getParamDecl(i);
145 QT = PVD->getType().getCanonicalType();
146
147 if (QT.getUnqualifiedType() != C.UnsignedIntTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800148 DiagEngine->Report(
149 clang::FullSourceLoc(PVD->getLocation(),
150 DiagEngine->getSourceManager()),
151 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines7b51b552012-02-16 00:12:38 -0800152 "Unexpected kernel %0() parameter '%1' "
153 "of type '%2'"))
154 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700155 valid = false;
156 } else {
157 llvm::StringRef ParamName = PVD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700158 if (ParamName.equals("x")) {
159 if (mX) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800160 ReportNameError(DiagEngine, PVD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700161 valid = false;
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700162 } else if (mY) {
163 // Can't go back to X after skipping Y
Logan Chien9207a2e2011-10-21 15:39:28 +0800164 ReportNameError(DiagEngine, PVD);
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700165 valid = false;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700166 } else {
167 mX = PVD;
168 }
169 } else if (ParamName.equals("y")) {
170 if (mY) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800171 ReportNameError(DiagEngine, PVD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700172 valid = false;
173 } else {
174 mY = PVD;
175 }
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700176 } else {
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700177 if (!mX && !mY) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700178 mX = PVD;
179 } else if (!mY) {
180 mY = PVD;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700181 } else {
Logan Chien9207a2e2011-10-21 15:39:28 +0800182 DiagEngine->Report(
183 clang::FullSourceLoc(PVD->getLocation(),
184 DiagEngine->getSourceManager()),
185 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines7b51b552012-02-16 00:12:38 -0800186 "Unexpected kernel %0() parameter '%1' "
187 "of type '%2'"))
188 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700189 valid = false;
190 }
191 }
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700192 }
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700193
194 i++;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700195 }
196
Stephen Hines7b51b552012-02-16 00:12:38 -0800197 mSignatureMetadata = 0;
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700198 if (valid) {
199 // Set up the bitwise metadata encoding for runtime argument passing.
Stephen Hines7b51b552012-02-16 00:12:38 -0800200 mSignatureMetadata |= (mIn ? 0x01 : 0);
201 mSignatureMetadata |= (mOut ? 0x02 : 0);
202 mSignatureMetadata |= (mUsrData ? 0x04 : 0);
203 mSignatureMetadata |= (mX ? 0x08 : 0);
204 mSignatureMetadata |= (mY ? 0x10 : 0);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700205 }
206
Stephen Hines12580dc2011-10-10 17:44:10 -0700207 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
208 // APIs before ICS cannot skip between parameters. It is ok, however, for
209 // them to omit further parameters (i.e. skipping X is ok if you skip Y).
Stephen Hines7b51b552012-02-16 00:12:38 -0800210 if (mSignatureMetadata != 0x1f && // In, Out, UsrData, X, Y
211 mSignatureMetadata != 0x0f && // In, Out, UsrData, X
212 mSignatureMetadata != 0x07 && // In, Out, UsrData
213 mSignatureMetadata != 0x03 && // In, Out
214 mSignatureMetadata != 0x01) { // In
Logan Chien9207a2e2011-10-21 15:39:28 +0800215 DiagEngine->Report(
216 clang::FullSourceLoc(FD->getLocation(),
217 DiagEngine->getSourceManager()),
218 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines7b51b552012-02-16 00:12:38 -0800219 "Compute kernel %0() targeting SDK levels "
220 "%1-%2 may not skip parameters"))
221 << FD->getName() << SLANG_MINIMUM_TARGET_API
222 << (SLANG_ICS_TARGET_API - 1);
Stephen Hines12580dc2011-10-10 17:44:10 -0700223 valid = false;
224 }
225 }
226
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700227 return valid;
228}
229
Stephen Hines9ca96e72012-09-13 16:57:06 -0700230
231bool RSExportForEach::validateAndConstructKernelParams(RSContext *Context,
232 const clang::FunctionDecl *FD) {
233 slangAssert(Context && FD);
234 bool valid = true;
235 clang::ASTContext &C = Context->getASTContext();
236 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
237
238 if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
239 DiagEngine->Report(
240 clang::FullSourceLoc(FD->getLocation(),
241 DiagEngine->getSourceManager()),
242 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
243 "Compute kernel %0() targeting SDK levels "
244 "%1-%2 may not use pass-by-value with "
245 "__attribute__((kernel))"))
246 << FD->getName() << SLANG_MINIMUM_TARGET_API
247 << (SLANG_JB_MR1_TARGET_API - 1);
248 return false;
249 }
250
251 // Denote that we are indeed a pass-by-value kernel.
252 mKernel = true;
253
254 if (mResultType != C.VoidTy) {
255 mReturn = true;
256 }
257
258 if (mResultType->isPointerType()) {
259 DiagEngine->Report(
260 clang::FullSourceLoc(FD->getTypeSpecStartLoc(),
261 DiagEngine->getSourceManager()),
262 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
263 "Compute kernel %0() cannot return a "
264 "pointer type: '%1'"))
265 << FD->getName() << mResultType.getAsString();
266 valid = false;
267 }
268
269 // Validate remaining parameter types
270 // TODO(all): Add support for LOD/face when we have them
271
272 size_t i = 0;
273 const clang::ParmVarDecl *PVD = NULL;
274 clang::QualType QT;
275
276 if (i < numParams) {
277 PVD = FD->getParamDecl(i);
278 QT = PVD->getType().getCanonicalType();
279
280 if (QT->isPointerType()) {
281 DiagEngine->Report(
282 clang::FullSourceLoc(PVD->getLocation(),
283 DiagEngine->getSourceManager()),
284 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
285 "Compute kernel %0() cannot have "
286 "parameter '%1' of pointer type: '%2'"))
287 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
288 valid = false;
289 } else if (QT.getUnqualifiedType() == C.UnsignedIntTy) {
290 // First parameter is either input or x, y (iff it is uint32_t).
291 llvm::StringRef ParamName = PVD->getName();
292 if (ParamName.equals("x")) {
293 mX = PVD;
294 } else if (ParamName.equals("y")) {
295 mY = PVD;
296 } else {
297 mIn = PVD;
298 }
299 } else {
300 mIn = PVD;
301 }
302
303 i++; // advance parameter pointer
304 }
305
306 // Check that we have at least one allocation to use for dimensions.
307 if (valid && !mIn && !mReturn) {
308 DiagEngine->Report(
309 clang::FullSourceLoc(FD->getLocation(),
310 DiagEngine->getSourceManager()),
311 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
312 "Compute kernel %0() must have at least one "
313 "input parameter or a non-void return "
314 "type")) << FD->getName();
315 valid = false;
316 }
317
318 // TODO: Abstract this block away, since it is duplicate code.
319 while (i < numParams) {
320 PVD = FD->getParamDecl(i);
321 QT = PVD->getType().getCanonicalType();
322
323 if (QT.getUnqualifiedType() != C.UnsignedIntTy) {
324 DiagEngine->Report(
325 clang::FullSourceLoc(PVD->getLocation(),
326 DiagEngine->getSourceManager()),
327 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
328 "Unexpected kernel %0() parameter '%1' "
329 "of type '%2'"))
330 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
331 valid = false;
332 } else {
333 llvm::StringRef ParamName = PVD->getName();
334 if (ParamName.equals("x")) {
335 if (mX) {
336 ReportNameError(DiagEngine, PVD);
337 valid = false;
338 } else if (mY) {
339 // Can't go back to X after skipping Y
340 ReportNameError(DiagEngine, PVD);
341 valid = false;
342 } else {
343 mX = PVD;
344 }
345 } else if (ParamName.equals("y")) {
346 if (mY) {
347 ReportNameError(DiagEngine, PVD);
348 valid = false;
349 } else {
350 mY = PVD;
351 }
352 } else {
353 if (!mX && !mY) {
354 mX = PVD;
355 } else if (!mY) {
356 mY = PVD;
357 } else {
358 DiagEngine->Report(
359 clang::FullSourceLoc(PVD->getLocation(),
360 DiagEngine->getSourceManager()),
361 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
362 "Unexpected kernel %0() parameter '%1' "
363 "of type '%2'"))
364 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
365 valid = false;
366 }
367 }
368 }
369
370 i++; // advance parameter pointer
371 }
372
373 mSignatureMetadata = 0;
374 if (valid) {
375 // Set up the bitwise metadata encoding for runtime argument passing.
376 mSignatureMetadata |= (mIn ? 0x01 : 0);
377 slangAssert(mOut == NULL);
378 mSignatureMetadata |= (mReturn ? 0x02 : 0);
379 slangAssert(mUsrData == NULL);
380 mSignatureMetadata |= (mUsrData ? 0x04 : 0);
381 mSignatureMetadata |= (mX ? 0x08 : 0);
382 mSignatureMetadata |= (mY ? 0x10 : 0);
383 mSignatureMetadata |= (mKernel ? 0x20 : 0); // pass-by-value
384 }
385
386 return valid;
387}
388
389
Stephen Hines593a8942011-05-10 15:29:50 -0700390RSExportForEach *RSExportForEach::Create(RSContext *Context,
391 const clang::FunctionDecl *FD) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700392 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700393 llvm::StringRef Name = FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700394 RSExportForEach *FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700395
396 slangAssert(!Name.empty() && "Function must have a name");
397
Stephen Hinesc17e1982012-02-22 12:30:45 -0800398 FE = new RSExportForEach(Context, Name);
Stephen Hines593a8942011-05-10 15:29:50 -0700399
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700400 if (!FE->validateAndConstructParams(Context, FD)) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700401 return NULL;
Stephen Hines593a8942011-05-10 15:29:50 -0700402 }
403
404 clang::ASTContext &Ctx = Context->getASTContext();
405
406 std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:");
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700407 Id.append(FE->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
Stephen Hines593a8942011-05-10 15:29:50 -0700408
409 // Extract the usrData parameter (if we have one)
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700410 if (FE->mUsrData) {
411 const clang::ParmVarDecl *PVD = FE->mUsrData;
Stephen Hines593a8942011-05-10 15:29:50 -0700412 clang::QualType QT = PVD->getType().getCanonicalType();
413 slangAssert(QT->isPointerType() &&
414 QT->getPointeeType().isConstQualified());
415
416 const clang::ASTContext &C = Context->getASTContext();
417 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
418 C.VoidTy) {
419 // In the case of using const void*, we can't reflect an appopriate
420 // Java type, so we fall back to just reflecting the ain/aout parameters
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700421 FE->mUsrData = NULL;
Stephen Hines593a8942011-05-10 15:29:50 -0700422 } else {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700423 clang::RecordDecl *RD =
424 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
425 Ctx.getTranslationUnitDecl(),
426 clang::SourceLocation(),
427 clang::SourceLocation(),
428 &Ctx.Idents.get(Id));
429
Stephen Hines593a8942011-05-10 15:29:50 -0700430 clang::FieldDecl *FD =
431 clang::FieldDecl::Create(Ctx,
432 RD,
433 clang::SourceLocation(),
434 clang::SourceLocation(),
435 PVD->getIdentifier(),
436 QT->getPointeeType(),
437 NULL,
Shih-wei Liao1688a3c2011-06-22 05:21:27 -0700438 /* BitWidth = */ NULL,
439 /* Mutable = */ false,
Shih-wei Liao43730fe2012-08-02 23:06:18 -0700440 /* HasInit = */ clang::ICIS_NoInit);
Stephen Hines593a8942011-05-10 15:29:50 -0700441 RD->addDecl(FD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700442 RD->completeDefinition();
443
444 // Create an export type iff we have a valid usrData type
445 clang::QualType T = Ctx.getTagDeclType(RD);
446 slangAssert(!T.isNull());
447
448 RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
449
450 if (ET == NULL) {
451 fprintf(stderr, "Failed to export the function %s. There's at least "
452 "one parameter whose type is not supported by the "
453 "reflection\n", FE->getName().c_str());
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700454 return NULL;
455 }
456
457 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
458 "Parameter packet must be a record");
459
460 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
Stephen Hines593a8942011-05-10 15:29:50 -0700461 }
462 }
Stephen Hines593a8942011-05-10 15:29:50 -0700463
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700464 if (FE->mIn) {
465 const clang::Type *T = FE->mIn->getType().getCanonicalType().getTypePtr();
466 FE->mInType = RSExportType::Create(Context, T);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700467 if (FE->mKernel) {
468 slangAssert(FE->mInType);
469 }
Stephen Hines593a8942011-05-10 15:29:50 -0700470 }
Stephen Hines5baf6322011-04-25 17:21:15 -0700471
Stephen Hines9ca96e72012-09-13 16:57:06 -0700472 if (FE->mKernel && FE->mReturn) {
473 const clang::Type *T = FE->mResultType.getTypePtr();
474 FE->mOutType = RSExportType::Create(Context, T);
475 slangAssert(FE->mOutType);
476 } else if (FE->mOut) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700477 const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
478 FE->mOutType = RSExportType::Create(Context, T);
479 }
480
481 return FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700482}
483
Stephen Hinesc17e1982012-02-22 12:30:45 -0800484RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
485 slangAssert(Context);
486 llvm::StringRef Name = "root";
487 RSExportForEach *FE = new RSExportForEach(Context, Name);
488 FE->mDummyRoot = true;
489 return FE;
490}
491
Stephen Hines9999ec32012-02-10 18:22:14 -0800492bool RSExportForEach::isGraphicsRootRSFunc(int targetAPI,
493 const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700494 if (FD->hasAttr<clang::KernelAttr>()) {
495 return false;
496 }
497
Stephen Hines9999ec32012-02-10 18:22:14 -0800498 if (!isRootRSFunc(FD)) {
499 return false;
500 }
501
502 if (FD->getNumParams() == 0) {
503 // Graphics root function
504 return true;
505 }
506
507 // Check for legacy graphics root function (with single parameter).
508 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
509 const clang::QualType &IntType = FD->getASTContext().IntTy;
510 if (FD->getResultType().getCanonicalType() == IntType) {
511 return true;
512 }
513 }
514
515 return false;
516}
517
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700518bool RSExportForEach::isRSForEachFunc(int targetAPI,
Stephen Hines089cde32012-12-07 19:19:10 -0800519 clang::DiagnosticsEngine *DiagEngine,
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700520 const clang::FunctionDecl *FD) {
Stephen Hines089cde32012-12-07 19:19:10 -0800521 slangAssert(DiagEngine && FD);
522 bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>();
523
524 if (FD->getStorageClass() == clang::SC_Static) {
525 if (hasKernelAttr) {
526 DiagEngine->Report(
527 clang::FullSourceLoc(FD->getLocation(),
528 DiagEngine->getSourceManager()),
529 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
530 "Invalid use of attribute kernel with "
531 "static function declaration: %0"))
532 << FD->getName();
533 }
534 return false;
535 }
536
Stephen Hines9ca96e72012-09-13 16:57:06 -0700537 // Anything tagged as a kernel is definitely used with ForEach.
Stephen Hines089cde32012-12-07 19:19:10 -0800538 if (hasKernelAttr) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700539 return true;
540 }
541
Stephen Hines9999ec32012-02-10 18:22:14 -0800542 if (isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700543 return false;
544 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700545
Stephen Hines7b51b552012-02-16 00:12:38 -0800546 // Check if first parameter is a pointer (which is required for ForEach).
547 unsigned int numParams = FD->getNumParams();
548
549 if (numParams > 0) {
550 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
551 clang::QualType QT = PVD->getType().getCanonicalType();
552
553 if (QT->isPointerType()) {
554 return true;
555 }
556
557 // Any non-graphics root() is automatically a ForEach candidate.
558 // At this point, however, we know that it is not going to be a valid
559 // compute root() function (due to not having a pointer parameter). We
560 // still want to return true here, so that we can issue appropriate
561 // diagnostics.
562 if (isRootRSFunc(FD)) {
563 return true;
564 }
565 }
566
567 return false;
Stephen Hines593a8942011-05-10 15:29:50 -0700568}
569
Logan Chien9207a2e2011-10-21 15:39:28 +0800570bool
Stephen Hinesfbfd7f52011-10-27 16:09:01 -0700571RSExportForEach::validateSpecialFuncDecl(int targetAPI,
572 clang::DiagnosticsEngine *DiagEngine,
Logan Chien9207a2e2011-10-21 15:39:28 +0800573 clang::FunctionDecl const *FD) {
574 slangAssert(DiagEngine && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700575 bool valid = true;
576 const clang::ASTContext &C = FD->getASTContext();
Stephen Hines9999ec32012-02-10 18:22:14 -0800577 const clang::QualType &IntType = FD->getASTContext().IntTy;
Stephen Hines5baf6322011-04-25 17:21:15 -0700578
Stephen Hines9999ec32012-02-10 18:22:14 -0800579 if (isGraphicsRootRSFunc(targetAPI, FD)) {
580 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
581 // Legacy graphics root function
582 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
583 clang::QualType QT = PVD->getType().getCanonicalType();
584 if (QT != IntType) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800585 DiagEngine->Report(
Stephen Hines9999ec32012-02-10 18:22:14 -0800586 clang::FullSourceLoc(PVD->getLocation(),
Logan Chien9207a2e2011-10-21 15:39:28 +0800587 DiagEngine->getSourceManager()),
588 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines9999ec32012-02-10 18:22:14 -0800589 "invalid parameter type for legacy "
590 "graphics root() function: %0"))
591 << PVD->getType();
Stephen Hines5baf6322011-04-25 17:21:15 -0700592 valid = false;
593 }
Stephen Hines9999ec32012-02-10 18:22:14 -0800594 }
595
596 // Graphics root function, so verify that it returns an int
597 if (FD->getResultType().getCanonicalType() != IntType) {
598 DiagEngine->Report(
599 clang::FullSourceLoc(FD->getLocation(),
600 DiagEngine->getSourceManager()),
601 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
602 "root() is required to return "
603 "an int for graphics usage"));
604 valid = false;
Stephen Hines5baf6322011-04-25 17:21:15 -0700605 }
Stephen Hines688e64b2011-08-23 16:01:25 -0700606 } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
Stephen Hines5baf6322011-04-25 17:21:15 -0700607 if (FD->getNumParams() != 0) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800608 DiagEngine->Report(
609 clang::FullSourceLoc(FD->getLocation(),
610 DiagEngine->getSourceManager()),
611 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
612 "%0(void) is required to have no "
613 "parameters")) << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700614 valid = false;
615 }
616
617 if (FD->getResultType().getCanonicalType() != C.VoidTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800618 DiagEngine->Report(
619 clang::FullSourceLoc(FD->getLocation(),
620 DiagEngine->getSourceManager()),
621 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
622 "%0(void) is required to have a void "
623 "return type")) << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700624 valid = false;
625 }
Stephen Hines3cb586a2011-05-05 18:20:22 -0700626 } else {
Stephen Hines688e64b2011-08-23 16:01:25 -0700627 slangAssert(false && "must be called on root, init or .rs.dtor function!");
Stephen Hines5baf6322011-04-25 17:21:15 -0700628 }
629
630 return valid;
631}
632
633} // namespace slang