blob: 439f9a9de74357025fc10e12ced67f3c69ff12fc [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"
Stephen Hines23c43582013-01-09 20:02:04 -080022#include "clang/AST/Attr.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070023#include "clang/AST/Decl.h"
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070024#include "clang/AST/TypeLoc.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070025
Stephen Hines23c43582013-01-09 20:02:04 -080026#include "llvm/IR/DerivedTypes.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070027
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 -070035// This function takes care of additional validation and construction of
36// parameters related to forEach_* reflection.
37bool RSExportForEach::validateAndConstructParams(
38 RSContext *Context, const clang::FunctionDecl *FD) {
39 slangAssert(Context && FD);
40 bool valid = true;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070041
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070042 numParams = FD->getNumParams();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070043
Stephen Hines7b51b552012-02-16 00:12:38 -080044 if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +000045 // Before JellyBean, we allowed only one kernel per file. It must be called "root".
Stephen Hines7b51b552012-02-16 00:12:38 -080046 if (!isRootRSFunc(FD)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080047 Context->ReportError(FD->getLocation(),
48 "Non-root compute kernel %0() is "
49 "not supported in SDK levels %1-%2")
50 << FD->getName() << SLANG_MINIMUM_TARGET_API
51 << (SLANG_JB_TARGET_API - 1);
Stephen Hines7b51b552012-02-16 00:12:38 -080052 return false;
53 }
54 }
55
Tim Murrayee4016d2014-04-10 15:49:08 -070056 mResultType = FD->getReturnType().getCanonicalType();
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080057 // Compute kernel functions are defined differently when the
58 // "__attribute__((kernel))" is set.
Stephen Hines9ca96e72012-09-13 16:57:06 -070059 if (FD->hasAttr<clang::KernelAttr>()) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080060 valid |= validateAndConstructKernelParams(Context, FD);
61 } else {
62 valid |= validateAndConstructOldStyleParams(Context, FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -070063 }
Chris Wailesc9454af2014-06-13 17:25:40 -070064
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080065 valid |= setSignatureMetadata(Context, FD);
66 return valid;
67}
Stephen Hines9ca96e72012-09-13 16:57:06 -070068
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -080069bool RSExportForEach::validateAndConstructOldStyleParams(
70 RSContext *Context, const clang::FunctionDecl *FD) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080071 slangAssert(Context && FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -070072 // If numParams is 0, we already marked this as a graphics root().
73 slangAssert(numParams > 0);
74
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080075 bool valid = true;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080076
77 // Compute kernel functions of this style are required to return a void type.
78 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -070079 if (mResultType != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080080 Context->ReportError(FD->getLocation(),
81 "Compute kernel %0() is required to return a "
82 "void type")
83 << FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070084 valid = false;
85 }
86
87 // Validate remaining parameter types
88 // TODO(all): Add support for LOD/face when we have them
89
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -080090 size_t IndexOfFirstIterator = numParams;
91 valid |= validateIterationParameters(Context, FD, &IndexOfFirstIterator);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070092
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -080093 // Validate the non-iterator parameters, which should all be found before the
94 // first iterator.
95 for (size_t i = 0; i < IndexOfFirstIterator; i++) {
96 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
97 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines4ccf75e2011-08-16 18:21:01 -070098
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -080099 if (!QT->isPointerType()) {
100 Context->ReportError(PVD->getLocation(),
101 "Compute kernel %0() cannot have non-pointer "
102 "parameters besides 'x' and 'y'. Parameter '%1' is "
103 "of type: '%2'")
104 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
105 valid = false;
106 continue;
107 }
108
109 // The only non-const pointer should be out.
110 if (!QT->getPointeeType().isConstQualified()) {
111 if (mOut == NULL) {
112 mOut = PVD;
113 } else {
114 Context->ReportError(PVD->getLocation(),
115 "Compute kernel %0() can only have one non-const "
116 "pointer parameter. Parameters '%1' and '%2' are "
117 "both non-const.")
118 << FD->getName() << mOut->getName() << PVD->getName();
119 valid = false;
120 }
121 } else {
Chris Wailesc9454af2014-06-13 17:25:40 -0700122 if (mIns.empty() && mOut == NULL) {
123 mIns.push_back(PVD);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800124 } else if (mUsrData == NULL) {
125 mUsrData = PVD;
126 } else {
127 Context->ReportError(
128 PVD->getLocation(),
129 "Unexpected parameter '%0' for compute kernel %1()")
130 << PVD->getName() << FD->getName();
131 valid = false;
132 }
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700133 }
134 }
135
Chris Wailesc9454af2014-06-13 17:25:40 -0700136 if (mIns.empty() && !mOut) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800137 Context->ReportError(FD->getLocation(),
138 "Compute kernel %0() must have at least one "
139 "parameter for in or out")
140 << FD->getName();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700141 valid = false;
142 }
143
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700144 return valid;
145}
146
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800147bool RSExportForEach::validateAndConstructKernelParams(
148 RSContext *Context, const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700149 slangAssert(Context && FD);
150 bool valid = true;
151 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700152
153 if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800154 Context->ReportError(FD->getLocation(),
155 "Compute kernel %0() targeting SDK levels "
156 "%1-%2 may not use pass-by-value with "
157 "__attribute__((kernel))")
158 << FD->getName() << SLANG_MINIMUM_TARGET_API
159 << (SLANG_JB_MR1_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700160 return false;
161 }
162
163 // Denote that we are indeed a pass-by-value kernel.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800164 mIsKernelStyle = true;
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800165 mHasReturnType = (mResultType != C.VoidTy);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700166
167 if (mResultType->isPointerType()) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800168 Context->ReportError(
169 FD->getTypeSpecStartLoc(),
170 "Compute kernel %0() cannot return a pointer type: '%1'")
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800171 << FD->getName() << mResultType.getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700172 valid = false;
173 }
174
175 // Validate remaining parameter types
176 // TODO(all): Add support for LOD/face when we have them
177
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800178 size_t IndexOfFirstIterator = numParams;
179 valid |= validateIterationParameters(Context, FD, &IndexOfFirstIterator);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700180
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800181 // Validate the non-iterator parameters, which should all be found before the
182 // first iterator.
183 for (size_t i = 0; i < IndexOfFirstIterator; i++) {
184 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
Chris Wailesc9454af2014-06-13 17:25:40 -0700185
186 /*
187 * FIXME: Change this to a test against an actual API version when the
188 * multi-input feature is officially supported.
189 */
190 if (Context->getTargetAPI() == SLANG_DEVELOPMENT_TARGET_API || i == 0) {
191 mIns.push_back(PVD);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800192 } else {
193 Context->ReportError(PVD->getLocation(),
Chris Wailesc9454af2014-06-13 17:25:40 -0700194 "Invalid parameter '%0' for compute kernel %1(). "
195 "Kernels targeting SDK levels %2-%3 may not use "
196 "multiple input parameters.") << PVD->getName() <<
197 FD->getName() << SLANG_MINIMUM_TARGET_API <<
198 SLANG_MAXIMUM_TARGET_API;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800199 valid = false;
200 }
201 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700202 if (QT->isPointerType()) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800203 Context->ReportError(PVD->getLocation(),
204 "Compute kernel %0() cannot have "
205 "parameter '%1' of pointer type: '%2'")
206 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700207 valid = false;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700208 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700209 }
210
211 // Check that we have at least one allocation to use for dimensions.
Chris Wailesc9454af2014-06-13 17:25:40 -0700212 if (valid && mIns.empty() && !mHasReturnType) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800213 Context->ReportError(FD->getLocation(),
214 "Compute kernel %0() must have at least one "
215 "input parameter or a non-void return "
216 "type")
217 << FD->getName();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700218 valid = false;
219 }
220
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800221 return valid;
222}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700223
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800224// Search for the optional x and y parameters. Returns true if valid. Also
225// sets *IndexOfFirstIterator to the index of the first iterator parameter, or
226// FD->getNumParams() if none are found.
227bool RSExportForEach::validateIterationParameters(
228 RSContext *Context, const clang::FunctionDecl *FD,
229 size_t *IndexOfFirstIterator) {
230 slangAssert(IndexOfFirstIterator != NULL);
231 slangAssert(mX == NULL && mY == NULL);
232 clang::ASTContext &C = Context->getASTContext();
233
234 // Find the x and y parameters if present.
235 size_t NumParams = FD->getNumParams();
236 *IndexOfFirstIterator = NumParams;
237 bool valid = true;
238 for (size_t i = 0; i < NumParams; i++) {
239 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
240 llvm::StringRef ParamName = PVD->getName();
241 if (ParamName.equals("x")) {
242 slangAssert(mX == NULL); // We won't be invoked if two 'x' are present.
243 mX = PVD;
244 if (mY != NULL) {
245 Context->ReportError(PVD->getLocation(),
246 "In compute kernel %0(), parameter 'x' should "
247 "be defined before parameter 'y'")
248 << FD->getName();
249 valid = false;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700250 }
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800251 } else if (ParamName.equals("y")) {
252 slangAssert(mY == NULL); // We won't be invoked if two 'y' are present.
253 mY = PVD;
254 } else {
255 // It's neither x nor y.
256 if (*IndexOfFirstIterator < NumParams) {
257 Context->ReportError(PVD->getLocation(),
258 "In compute kernel %0(), parameter '%1' cannot "
259 "appear after the 'x' and 'y' parameters")
260 << FD->getName() << ParamName;
261 valid = false;
262 }
263 continue;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700264 }
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800265 // Validate the data type of x and y.
266 clang::QualType QT = PVD->getType().getCanonicalType();
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000267 clang::QualType UT = QT.getUnqualifiedType();
268 if (UT != C.UnsignedIntTy && UT != C.IntTy) {
269 Context->ReportError(PVD->getLocation(),
270 "Parameter '%0' must be of type 'int' or "
271 "'unsigned int'. It is of type '%1'")
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800272 << ParamName << PVD->getType().getAsString();
273 valid = false;
274 }
275 // If this is the first time we find an iterator, save it.
276 if (*IndexOfFirstIterator >= NumParams) {
277 *IndexOfFirstIterator = i;
278 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700279 }
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000280 // Check that x and y have the same type.
281 if (mX != NULL and mY != NULL) {
282 clang::QualType XType = mX->getType();
283 clang::QualType YType = mY->getType();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700284
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000285 if (XType != YType) {
286 Context->ReportError(mY->getLocation(),
287 "Parameter 'x' and 'y' must be of the same type. "
288 "'x' is of type '%0' while 'y' is of type '%1'")
289 << XType.getAsString() << YType.getAsString();
290 valid = false;
291 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700292 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700293 return valid;
294}
295
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800296bool RSExportForEach::setSignatureMetadata(RSContext *Context,
297 const clang::FunctionDecl *FD) {
298 mSignatureMetadata = 0;
299 bool valid = true;
300
301 if (mIsKernelStyle) {
302 slangAssert(mOut == NULL);
303 slangAssert(mUsrData == NULL);
304 } else {
305 slangAssert(!mHasReturnType);
306 }
307
308 // Set up the bitwise metadata encoding for runtime argument passing.
309 // TODO: If this bit field is re-used from C++ code, define the values in a header.
310 const bool HasOut = mOut || mHasReturnType;
Chris Wailesc9454af2014-06-13 17:25:40 -0700311 mSignatureMetadata |= (hasIns() ? 0x01 : 0);
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800312 mSignatureMetadata |= (HasOut ? 0x02 : 0);
313 mSignatureMetadata |= (mUsrData ? 0x04 : 0);
314 mSignatureMetadata |= (mX ? 0x08 : 0);
315 mSignatureMetadata |= (mY ? 0x10 : 0);
316 mSignatureMetadata |= (mIsKernelStyle ? 0x20 : 0); // pass-by-value
317
318 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
319 // APIs before ICS cannot skip between parameters. It is ok, however, for
320 // them to omit further parameters (i.e. skipping X is ok if you skip Y).
321 if (mSignatureMetadata != 0x1f && // In, Out, UsrData, X, Y
322 mSignatureMetadata != 0x0f && // In, Out, UsrData, X
323 mSignatureMetadata != 0x07 && // In, Out, UsrData
324 mSignatureMetadata != 0x03 && // In, Out
325 mSignatureMetadata != 0x01) { // In
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800326 Context->ReportError(FD->getLocation(),
327 "Compute kernel %0() targeting SDK levels "
328 "%1-%2 may not skip parameters")
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800329 << FD->getName() << SLANG_MINIMUM_TARGET_API
330 << (SLANG_ICS_TARGET_API - 1);
331 valid = false;
332 }
333 }
334 return valid;
335}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700336
Stephen Hines593a8942011-05-10 15:29:50 -0700337RSExportForEach *RSExportForEach::Create(RSContext *Context,
338 const clang::FunctionDecl *FD) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700339 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700340 llvm::StringRef Name = FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700341 RSExportForEach *FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700342
343 slangAssert(!Name.empty() && "Function must have a name");
344
Stephen Hinesc17e1982012-02-22 12:30:45 -0800345 FE = new RSExportForEach(Context, Name);
Stephen Hines593a8942011-05-10 15:29:50 -0700346
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700347 if (!FE->validateAndConstructParams(Context, FD)) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700348 return NULL;
Stephen Hines593a8942011-05-10 15:29:50 -0700349 }
350
351 clang::ASTContext &Ctx = Context->getASTContext();
352
Jean-Luc Brouilleteca05342014-05-15 12:44:21 -0700353 std::string Id = CreateDummyName("helper_foreach_param", FE->getName());
Stephen Hines593a8942011-05-10 15:29:50 -0700354
355 // Extract the usrData parameter (if we have one)
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700356 if (FE->mUsrData) {
357 const clang::ParmVarDecl *PVD = FE->mUsrData;
Stephen Hines593a8942011-05-10 15:29:50 -0700358 clang::QualType QT = PVD->getType().getCanonicalType();
359 slangAssert(QT->isPointerType() &&
360 QT->getPointeeType().isConstQualified());
361
362 const clang::ASTContext &C = Context->getASTContext();
363 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
364 C.VoidTy) {
365 // In the case of using const void*, we can't reflect an appopriate
366 // Java type, so we fall back to just reflecting the ain/aout parameters
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700367 FE->mUsrData = NULL;
Stephen Hines593a8942011-05-10 15:29:50 -0700368 } else {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700369 clang::RecordDecl *RD =
370 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
371 Ctx.getTranslationUnitDecl(),
372 clang::SourceLocation(),
373 clang::SourceLocation(),
374 &Ctx.Idents.get(Id));
375
Stephen Hines593a8942011-05-10 15:29:50 -0700376 clang::FieldDecl *FD =
377 clang::FieldDecl::Create(Ctx,
378 RD,
379 clang::SourceLocation(),
380 clang::SourceLocation(),
381 PVD->getIdentifier(),
382 QT->getPointeeType(),
383 NULL,
Shih-wei Liao1688a3c2011-06-22 05:21:27 -0700384 /* BitWidth = */ NULL,
385 /* Mutable = */ false,
Shih-wei Liao43730fe2012-08-02 23:06:18 -0700386 /* HasInit = */ clang::ICIS_NoInit);
Stephen Hines593a8942011-05-10 15:29:50 -0700387 RD->addDecl(FD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700388 RD->completeDefinition();
389
390 // Create an export type iff we have a valid usrData type
391 clang::QualType T = Ctx.getTagDeclType(RD);
392 slangAssert(!T.isNull());
393
394 RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
395
396 if (ET == NULL) {
397 fprintf(stderr, "Failed to export the function %s. There's at least "
398 "one parameter whose type is not supported by the "
399 "reflection\n", FE->getName().c_str());
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700400 return NULL;
401 }
402
403 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
404 "Parameter packet must be a record");
405
406 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
Stephen Hines593a8942011-05-10 15:29:50 -0700407 }
408 }
Stephen Hines593a8942011-05-10 15:29:50 -0700409
Chris Wailesc9454af2014-06-13 17:25:40 -0700410 if (FE->hasIns()) {
411
412 for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
413 const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
414 RSExportType *InExportType = RSExportType::Create(Context, T);
415
416 if (FE->mIsKernelStyle) {
417 slangAssert(InExportType != NULL);
418 }
419
420 FE->mInTypes.push_back(InExportType);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700421 }
Stephen Hines593a8942011-05-10 15:29:50 -0700422 }
Stephen Hines5baf6322011-04-25 17:21:15 -0700423
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800424 if (FE->mIsKernelStyle && FE->mHasReturnType) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700425 const clang::Type *T = FE->mResultType.getTypePtr();
426 FE->mOutType = RSExportType::Create(Context, T);
427 slangAssert(FE->mOutType);
428 } else if (FE->mOut) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700429 const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
430 FE->mOutType = RSExportType::Create(Context, T);
431 }
432
433 return FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700434}
435
Stephen Hinesc17e1982012-02-22 12:30:45 -0800436RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
437 slangAssert(Context);
438 llvm::StringRef Name = "root";
439 RSExportForEach *FE = new RSExportForEach(Context, Name);
440 FE->mDummyRoot = true;
441 return FE;
442}
443
Chris Wailesc9454af2014-06-13 17:25:40 -0700444bool RSExportForEach::isGraphicsRootRSFunc(unsigned int targetAPI,
Stephen Hines9999ec32012-02-10 18:22:14 -0800445 const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700446 if (FD->hasAttr<clang::KernelAttr>()) {
447 return false;
448 }
449
Stephen Hines9999ec32012-02-10 18:22:14 -0800450 if (!isRootRSFunc(FD)) {
451 return false;
452 }
453
454 if (FD->getNumParams() == 0) {
455 // Graphics root function
456 return true;
457 }
458
459 // Check for legacy graphics root function (with single parameter).
460 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
461 const clang::QualType &IntType = FD->getASTContext().IntTy;
Tim Murrayee4016d2014-04-10 15:49:08 -0700462 if (FD->getReturnType().getCanonicalType() == IntType) {
Stephen Hines9999ec32012-02-10 18:22:14 -0800463 return true;
464 }
465 }
466
467 return false;
468}
469
Chris Wailesc9454af2014-06-13 17:25:40 -0700470bool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
471 slang::RSContext* Context,
472 const clang::FunctionDecl *FD) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800473 slangAssert(Context && FD);
Stephen Hines089cde32012-12-07 19:19:10 -0800474 bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>();
475
476 if (FD->getStorageClass() == clang::SC_Static) {
477 if (hasKernelAttr) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800478 Context->ReportError(FD->getLocation(),
479 "Invalid use of attribute kernel with "
480 "static function declaration: %0")
481 << FD->getName();
Stephen Hines089cde32012-12-07 19:19:10 -0800482 }
483 return false;
484 }
485
Stephen Hines9ca96e72012-09-13 16:57:06 -0700486 // Anything tagged as a kernel is definitely used with ForEach.
Stephen Hines089cde32012-12-07 19:19:10 -0800487 if (hasKernelAttr) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700488 return true;
489 }
490
Stephen Hines9999ec32012-02-10 18:22:14 -0800491 if (isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700492 return false;
493 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700494
Stephen Hines7b51b552012-02-16 00:12:38 -0800495 // Check if first parameter is a pointer (which is required for ForEach).
496 unsigned int numParams = FD->getNumParams();
497
498 if (numParams > 0) {
499 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
500 clang::QualType QT = PVD->getType().getCanonicalType();
501
502 if (QT->isPointerType()) {
503 return true;
504 }
505
506 // Any non-graphics root() is automatically a ForEach candidate.
507 // At this point, however, we know that it is not going to be a valid
508 // compute root() function (due to not having a pointer parameter). We
509 // still want to return true here, so that we can issue appropriate
510 // diagnostics.
511 if (isRootRSFunc(FD)) {
512 return true;
513 }
514 }
515
516 return false;
Stephen Hines593a8942011-05-10 15:29:50 -0700517}
518
Logan Chien9207a2e2011-10-21 15:39:28 +0800519bool
Chris Wailesc9454af2014-06-13 17:25:40 -0700520RSExportForEach::validateSpecialFuncDecl(unsigned int targetAPI,
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800521 slang::RSContext *Context,
Logan Chien9207a2e2011-10-21 15:39:28 +0800522 clang::FunctionDecl const *FD) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800523 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700524 bool valid = true;
525 const clang::ASTContext &C = FD->getASTContext();
Stephen Hines9999ec32012-02-10 18:22:14 -0800526 const clang::QualType &IntType = FD->getASTContext().IntTy;
Stephen Hines5baf6322011-04-25 17:21:15 -0700527
Stephen Hines9999ec32012-02-10 18:22:14 -0800528 if (isGraphicsRootRSFunc(targetAPI, FD)) {
529 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
530 // Legacy graphics root function
531 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
532 clang::QualType QT = PVD->getType().getCanonicalType();
533 if (QT != IntType) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800534 Context->ReportError(PVD->getLocation(),
535 "invalid parameter type for legacy "
536 "graphics root() function: %0")
537 << PVD->getType();
Stephen Hines5baf6322011-04-25 17:21:15 -0700538 valid = false;
539 }
Stephen Hines9999ec32012-02-10 18:22:14 -0800540 }
541
542 // Graphics root function, so verify that it returns an int
Tim Murrayee4016d2014-04-10 15:49:08 -0700543 if (FD->getReturnType().getCanonicalType() != IntType) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800544 Context->ReportError(FD->getLocation(),
545 "root() is required to return "
546 "an int for graphics usage");
Stephen Hines9999ec32012-02-10 18:22:14 -0800547 valid = false;
Stephen Hines5baf6322011-04-25 17:21:15 -0700548 }
Stephen Hines688e64b2011-08-23 16:01:25 -0700549 } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
Stephen Hines5baf6322011-04-25 17:21:15 -0700550 if (FD->getNumParams() != 0) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800551 Context->ReportError(FD->getLocation(),
552 "%0(void) is required to have no "
553 "parameters")
554 << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700555 valid = false;
556 }
557
Tim Murrayee4016d2014-04-10 15:49:08 -0700558 if (FD->getReturnType().getCanonicalType() != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800559 Context->ReportError(FD->getLocation(),
560 "%0(void) is required to have a void "
561 "return type")
562 << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700563 valid = false;
564 }
Stephen Hines3cb586a2011-05-05 18:20:22 -0700565 } else {
Stephen Hines688e64b2011-08-23 16:01:25 -0700566 slangAssert(false && "must be called on root, init or .rs.dtor function!");
Stephen Hines5baf6322011-04-25 17:21:15 -0700567 }
568
569 return valid;
570}
571
572} // namespace slang