blob: 5754b4191644f28b884cf4b751a8758e08e8e581 [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,
519 const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700520 // Anything tagged as a kernel is definitely used with ForEach.
521 if (FD->hasAttr<clang::KernelAttr>()) {
522 return true;
523 }
524
Stephen Hines9999ec32012-02-10 18:22:14 -0800525 if (isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700526 return false;
527 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700528
Stephen Hines7b51b552012-02-16 00:12:38 -0800529 // Check if first parameter is a pointer (which is required for ForEach).
530 unsigned int numParams = FD->getNumParams();
531
532 if (numParams > 0) {
533 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
534 clang::QualType QT = PVD->getType().getCanonicalType();
535
536 if (QT->isPointerType()) {
537 return true;
538 }
539
540 // Any non-graphics root() is automatically a ForEach candidate.
541 // At this point, however, we know that it is not going to be a valid
542 // compute root() function (due to not having a pointer parameter). We
543 // still want to return true here, so that we can issue appropriate
544 // diagnostics.
545 if (isRootRSFunc(FD)) {
546 return true;
547 }
548 }
549
550 return false;
Stephen Hines593a8942011-05-10 15:29:50 -0700551}
552
Logan Chien9207a2e2011-10-21 15:39:28 +0800553bool
Stephen Hinesfbfd7f52011-10-27 16:09:01 -0700554RSExportForEach::validateSpecialFuncDecl(int targetAPI,
555 clang::DiagnosticsEngine *DiagEngine,
Logan Chien9207a2e2011-10-21 15:39:28 +0800556 clang::FunctionDecl const *FD) {
557 slangAssert(DiagEngine && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700558 bool valid = true;
559 const clang::ASTContext &C = FD->getASTContext();
Stephen Hines9999ec32012-02-10 18:22:14 -0800560 const clang::QualType &IntType = FD->getASTContext().IntTy;
Stephen Hines5baf6322011-04-25 17:21:15 -0700561
Stephen Hines9999ec32012-02-10 18:22:14 -0800562 if (isGraphicsRootRSFunc(targetAPI, FD)) {
563 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
564 // Legacy graphics root function
565 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
566 clang::QualType QT = PVD->getType().getCanonicalType();
567 if (QT != IntType) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800568 DiagEngine->Report(
Stephen Hines9999ec32012-02-10 18:22:14 -0800569 clang::FullSourceLoc(PVD->getLocation(),
Logan Chien9207a2e2011-10-21 15:39:28 +0800570 DiagEngine->getSourceManager()),
571 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines9999ec32012-02-10 18:22:14 -0800572 "invalid parameter type for legacy "
573 "graphics root() function: %0"))
574 << PVD->getType();
Stephen Hines5baf6322011-04-25 17:21:15 -0700575 valid = false;
576 }
Stephen Hines9999ec32012-02-10 18:22:14 -0800577 }
578
579 // Graphics root function, so verify that it returns an int
580 if (FD->getResultType().getCanonicalType() != IntType) {
581 DiagEngine->Report(
582 clang::FullSourceLoc(FD->getLocation(),
583 DiagEngine->getSourceManager()),
584 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
585 "root() is required to return "
586 "an int for graphics usage"));
587 valid = false;
Stephen Hines5baf6322011-04-25 17:21:15 -0700588 }
Stephen Hines688e64b2011-08-23 16:01:25 -0700589 } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
Stephen Hines5baf6322011-04-25 17:21:15 -0700590 if (FD->getNumParams() != 0) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800591 DiagEngine->Report(
592 clang::FullSourceLoc(FD->getLocation(),
593 DiagEngine->getSourceManager()),
594 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
595 "%0(void) is required to have no "
596 "parameters")) << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700597 valid = false;
598 }
599
600 if (FD->getResultType().getCanonicalType() != C.VoidTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800601 DiagEngine->Report(
602 clang::FullSourceLoc(FD->getLocation(),
603 DiagEngine->getSourceManager()),
604 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
605 "%0(void) is required to have a void "
606 "return type")) << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700607 valid = false;
608 }
Stephen Hines3cb586a2011-05-05 18:20:22 -0700609 } else {
Stephen Hines688e64b2011-08-23 16:01:25 -0700610 slangAssert(false && "must be called on root, init or .rs.dtor function!");
Stephen Hines5baf6322011-04-25 17:21:15 -0700611 }
612
613 return valid;
614}
615
616} // namespace slang