blob: 8fc693bed975f5c17133f75f43d3218a1d458b20 [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
David Gross18c50eb2015-01-30 11:39:22 -080028#include "bcinfo/MetadataExtractor.h"
29
Stephen Hines5baf6322011-04-25 17:21:15 -070030#include "slang_assert.h"
31#include "slang_rs_context.h"
Stephen Hines593a8942011-05-10 15:29:50 -070032#include "slang_rs_export_type.h"
Matt Walaeae0b7a2015-06-16 14:06:25 -070033#include "slang_rs_special_func.h"
David Gross46e146e2015-11-11 15:14:01 -080034#include "slang_rs_special_kernel_param.h"
Stephen Hines12580dc2011-10-10 17:44:10 -070035#include "slang_version.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070036
David Gross18c50eb2015-01-30 11:39:22 -080037namespace {
38
David Grosscd7d3122015-03-13 15:11:44 -070039const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
40
Matt Walaeae0b7a2015-06-16 14:06:25 -070041bool isRootRSFunc(const clang::FunctionDecl *FD) {
42 if (!FD) {
43 return false;
44 }
45 return FD->getName().equals("root");
David Gross7cc68762015-03-11 14:29:24 -070046}
David Gross18c50eb2015-01-30 11:39:22 -080047
Matt Walaeae0b7a2015-06-16 14:06:25 -070048} // end anonymous namespace
49
Stephen Hines5baf6322011-04-25 17:21:15 -070050namespace slang {
51
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070052// This function takes care of additional validation and construction of
53// parameters related to forEach_* reflection.
54bool RSExportForEach::validateAndConstructParams(
55 RSContext *Context, const clang::FunctionDecl *FD) {
56 slangAssert(Context && FD);
57 bool valid = true;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070058
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070059 numParams = FD->getNumParams();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070060
Stephen Hines7b51b552012-02-16 00:12:38 -080061 if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +000062 // Before JellyBean, we allowed only one kernel per file. It must be called "root".
Stephen Hines7b51b552012-02-16 00:12:38 -080063 if (!isRootRSFunc(FD)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080064 Context->ReportError(FD->getLocation(),
65 "Non-root compute kernel %0() is "
66 "not supported in SDK levels %1-%2")
67 << FD->getName() << SLANG_MINIMUM_TARGET_API
68 << (SLANG_JB_TARGET_API - 1);
Stephen Hines7b51b552012-02-16 00:12:38 -080069 return false;
70 }
71 }
72
Tim Murrayee4016d2014-04-10 15:49:08 -070073 mResultType = FD->getReturnType().getCanonicalType();
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080074 // Compute kernel functions are defined differently when the
75 // "__attribute__((kernel))" is set.
Pirama Arumuga Nainarb6a14352016-07-26 11:39:47 -070076 if (FD->hasAttr<clang::RenderScriptKernelAttr>()) {
Stephen Hinesf075ffc2015-12-03 03:07:55 -080077 valid &= validateAndConstructKernelParams(Context, FD);
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080078 } else {
Stephen Hinesf075ffc2015-12-03 03:07:55 -080079 valid &= validateAndConstructOldStyleParams(Context, FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -070080 }
Chris Wailesc9454af2014-06-13 17:25:40 -070081
Stephen Hinesf075ffc2015-12-03 03:07:55 -080082 valid &= setSignatureMetadata(Context, FD);
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080083 return valid;
84}
Stephen Hines9ca96e72012-09-13 16:57:06 -070085
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -080086bool RSExportForEach::validateAndConstructOldStyleParams(
87 RSContext *Context, const clang::FunctionDecl *FD) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080088 slangAssert(Context && FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -070089 // If numParams is 0, we already marked this as a graphics root().
90 slangAssert(numParams > 0);
91
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080092 bool valid = true;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -080093
94 // Compute kernel functions of this style are required to return a void type.
95 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -070096 if (mResultType != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -080097 Context->ReportError(FD->getLocation(),
98 "Compute kernel %0() is required to return a "
99 "void type")
100 << FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700101 valid = false;
102 }
103
104 // Validate remaining parameter types
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700105
David Gross18c50eb2015-01-30 11:39:22 -0800106 size_t IndexOfFirstSpecialParameter = numParams;
Stephen Hinesf075ffc2015-12-03 03:07:55 -0800107 valid &= processSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700108
David Gross18c50eb2015-01-30 11:39:22 -0800109 // Validate the non-special parameters, which should all be found before the
110 // first special parameter.
111 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800112 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
113 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700114
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800115 if (!QT->isPointerType()) {
116 Context->ReportError(PVD->getLocation(),
117 "Compute kernel %0() cannot have non-pointer "
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700118 "parameters besides special parameters (%1). Parameter '%2' is "
David Gross18c50eb2015-01-30 11:39:22 -0800119 "of type: '%3'")
David Gross46e146e2015-11-11 15:14:01 -0800120 << FD->getName() << listSpecialKernelParameters(Context->getTargetAPI())
David Gross18c50eb2015-01-30 11:39:22 -0800121 << PVD->getName() << PVD->getType().getAsString();
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800122 valid = false;
123 continue;
124 }
125
126 // The only non-const pointer should be out.
127 if (!QT->getPointeeType().isConstQualified()) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700128 if (mOut == nullptr) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800129 mOut = PVD;
130 } else {
131 Context->ReportError(PVD->getLocation(),
132 "Compute kernel %0() can only have one non-const "
133 "pointer parameter. Parameters '%1' and '%2' are "
134 "both non-const.")
135 << FD->getName() << mOut->getName() << PVD->getName();
136 valid = false;
137 }
138 } else {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700139 if (mIns.empty() && mOut == nullptr) {
Chris Wailesc9454af2014-06-13 17:25:40 -0700140 mIns.push_back(PVD);
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700141 } else if (mUsrData == nullptr) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800142 mUsrData = PVD;
143 } else {
144 Context->ReportError(
145 PVD->getLocation(),
146 "Unexpected parameter '%0' for compute kernel %1()")
147 << PVD->getName() << FD->getName();
148 valid = false;
149 }
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700150 }
151 }
152
Chris Wailesc9454af2014-06-13 17:25:40 -0700153 if (mIns.empty() && !mOut) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800154 Context->ReportError(FD->getLocation(),
155 "Compute kernel %0() must have at least one "
156 "parameter for in or out")
157 << FD->getName();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700158 valid = false;
159 }
160
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700161 return valid;
162}
163
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800164bool RSExportForEach::validateAndConstructKernelParams(
165 RSContext *Context, const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700166 slangAssert(Context && FD);
167 bool valid = true;
168 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700169
170 if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800171 Context->ReportError(FD->getLocation(),
172 "Compute kernel %0() targeting SDK levels "
173 "%1-%2 may not use pass-by-value with "
174 "__attribute__((kernel))")
175 << FD->getName() << SLANG_MINIMUM_TARGET_API
176 << (SLANG_JB_MR1_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700177 return false;
178 }
179
180 // Denote that we are indeed a pass-by-value kernel.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800181 mIsKernelStyle = true;
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800182 mHasReturnType = (mResultType != C.VoidTy);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700183
184 if (mResultType->isPointerType()) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800185 Context->ReportError(
186 FD->getTypeSpecStartLoc(),
187 "Compute kernel %0() cannot return a pointer type: '%1'")
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800188 << FD->getName() << mResultType.getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700189 valid = false;
190 }
191
192 // Validate remaining parameter types
Stephen Hines9ca96e72012-09-13 16:57:06 -0700193
David Gross18c50eb2015-01-30 11:39:22 -0800194 size_t IndexOfFirstSpecialParameter = numParams;
Stephen Hinesf075ffc2015-12-03 03:07:55 -0800195 valid &= processSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700196
David Gross18c50eb2015-01-30 11:39:22 -0800197 // Validate the non-special parameters, which should all be found before the
198 // first special.
199 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800200 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
Chris Wailesc9454af2014-06-13 17:25:40 -0700201
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700202 if (Context->getTargetAPI() >= SLANG_M_TARGET_API || i == 0) {
David Grosscd7d3122015-03-13 15:11:44 -0700203 if (i >= RS_KERNEL_INPUT_LIMIT) {
204 Context->ReportError(PVD->getLocation(),
205 "Invalid parameter '%0' for compute kernel %1(). "
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700206 "Kernels targeting SDK levels %2+ may not use "
207 "more than %3 input parameters.") << PVD->getName() <<
208 FD->getName() << SLANG_M_TARGET_API <<
209 int(RS_KERNEL_INPUT_LIMIT);
David Grosscd7d3122015-03-13 15:11:44 -0700210
211 } else {
212 mIns.push_back(PVD);
213 }
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800214 } else {
215 Context->ReportError(PVD->getLocation(),
Chris Wailesc9454af2014-06-13 17:25:40 -0700216 "Invalid parameter '%0' for compute kernel %1(). "
217 "Kernels targeting SDK levels %2-%3 may not use "
218 "multiple input parameters.") << PVD->getName() <<
219 FD->getName() << SLANG_MINIMUM_TARGET_API <<
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700220 (SLANG_M_TARGET_API - 1);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800221 valid = false;
222 }
223 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700224 if (QT->isPointerType()) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800225 Context->ReportError(PVD->getLocation(),
226 "Compute kernel %0() cannot have "
227 "parameter '%1' of pointer type: '%2'")
228 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700229 valid = false;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700230 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700231 }
232
233 // Check that we have at least one allocation to use for dimensions.
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700234 if (valid && mIns.empty() && !mHasReturnType && Context->getTargetAPI() < SLANG_M_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800235 Context->ReportError(FD->getLocation(),
David Grossfb78d4c2015-03-31 13:56:05 -0700236 "Compute kernel %0() targeting SDK levels "
237 "%1-%2 must have at least one "
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800238 "input parameter or a non-void return "
239 "type")
David Grossfb78d4c2015-03-31 13:56:05 -0700240 << FD->getName() << SLANG_MINIMUM_TARGET_API
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700241 << (SLANG_M_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700242 valid = false;
243 }
244
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800245 return valid;
246}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700247
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700248// Process the optional special parameters:
249// - Sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or
250// FD->getNumParams() if none are found.
David Gross46e146e2015-11-11 15:14:01 -0800251// - Add bits to mSpecialParameterSignatureMetadata for the found special parameters.
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700252// Returns true if no errors.
253bool RSExportForEach::processSpecialParameters(
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800254 RSContext *Context, const clang::FunctionDecl *FD,
David Gross18c50eb2015-01-30 11:39:22 -0800255 size_t *IndexOfFirstSpecialParameter) {
David Gross46e146e2015-11-11 15:14:01 -0800256 auto DiagnosticCallback = [FD] {
257 std::ostringstream DiagnosticDescription;
258 DiagnosticDescription << "compute kernel " << FD->getName().str() << "()";
259 return DiagnosticDescription.str();
260 };
261 return slang::processSpecialKernelParameters(Context,
262 DiagnosticCallback,
263 FD,
264 IndexOfFirstSpecialParameter,
265 &mSpecialParameterSignatureMetadata);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700266}
267
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800268bool RSExportForEach::setSignatureMetadata(RSContext *Context,
269 const clang::FunctionDecl *FD) {
270 mSignatureMetadata = 0;
271 bool valid = true;
272
273 if (mIsKernelStyle) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700274 slangAssert(mOut == nullptr);
275 slangAssert(mUsrData == nullptr);
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800276 } else {
277 slangAssert(!mHasReturnType);
278 }
279
280 // Set up the bitwise metadata encoding for runtime argument passing.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800281 const bool HasOut = mOut || mHasReturnType;
David Gross18c50eb2015-01-30 11:39:22 -0800282 mSignatureMetadata |= (hasIns() ? bcinfo::MD_SIG_In : 0);
283 mSignatureMetadata |= (HasOut ? bcinfo::MD_SIG_Out : 0);
284 mSignatureMetadata |= (mUsrData ? bcinfo::MD_SIG_Usr : 0);
285 mSignatureMetadata |= (mIsKernelStyle ? bcinfo::MD_SIG_Kernel : 0); // pass-by-value
286 mSignatureMetadata |= mSpecialParameterSignatureMetadata;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800287
288 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
289 // APIs before ICS cannot skip between parameters. It is ok, however, for
290 // them to omit further parameters (i.e. skipping X is ok if you skip Y).
David Gross18c50eb2015-01-30 11:39:22 -0800291 if (mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
292 bcinfo::MD_SIG_X | bcinfo::MD_SIG_Y) &&
293 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
294 bcinfo::MD_SIG_X) &&
295 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr) &&
296 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out) &&
297 mSignatureMetadata != (bcinfo::MD_SIG_In)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800298 Context->ReportError(FD->getLocation(),
299 "Compute kernel %0() targeting SDK levels "
300 "%1-%2 may not skip parameters")
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800301 << FD->getName() << SLANG_MINIMUM_TARGET_API
302 << (SLANG_ICS_TARGET_API - 1);
303 valid = false;
304 }
305 }
306 return valid;
307}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700308
Stephen Hines593a8942011-05-10 15:29:50 -0700309RSExportForEach *RSExportForEach::Create(RSContext *Context,
310 const clang::FunctionDecl *FD) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700311 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700312 llvm::StringRef Name = FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700313 RSExportForEach *FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700314
315 slangAssert(!Name.empty() && "Function must have a name");
316
David Gross63e61082017-07-13 14:17:29 -0700317 FE = new RSExportForEach(Context, Name, FD->getLocation());
David Grossd80e58b2017-07-24 11:41:12 -0700318 FE->mOrdinal = Context->getNextForEachOrdinal();
Stephen Hines593a8942011-05-10 15:29:50 -0700319
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700320 if (!FE->validateAndConstructParams(Context, FD)) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700321 return nullptr;
Stephen Hines593a8942011-05-10 15:29:50 -0700322 }
323
324 clang::ASTContext &Ctx = Context->getASTContext();
325
Jean-Luc Brouilleteca05342014-05-15 12:44:21 -0700326 std::string Id = CreateDummyName("helper_foreach_param", FE->getName());
Stephen Hines593a8942011-05-10 15:29:50 -0700327
David Gross50ff2632017-07-06 14:12:46 -0700328 // Construct type information about usrData, inputs, and
329 // outputs. Return null when there is an error exporting types.
330
331 bool TypeExportError = false;
332
Stephen Hines593a8942011-05-10 15:29:50 -0700333 // Extract the usrData parameter (if we have one)
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700334 if (FE->mUsrData) {
335 const clang::ParmVarDecl *PVD = FE->mUsrData;
Stephen Hines593a8942011-05-10 15:29:50 -0700336 clang::QualType QT = PVD->getType().getCanonicalType();
337 slangAssert(QT->isPointerType() &&
338 QT->getPointeeType().isConstQualified());
339
340 const clang::ASTContext &C = Context->getASTContext();
341 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
342 C.VoidTy) {
343 // In the case of using const void*, we can't reflect an appopriate
344 // Java type, so we fall back to just reflecting the ain/aout parameters
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700345 FE->mUsrData = nullptr;
Stephen Hines593a8942011-05-10 15:29:50 -0700346 } else {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700347 clang::RecordDecl *RD =
348 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
349 Ctx.getTranslationUnitDecl(),
350 clang::SourceLocation(),
351 clang::SourceLocation(),
352 &Ctx.Idents.get(Id));
353
Stephen Hines593a8942011-05-10 15:29:50 -0700354 clang::FieldDecl *FD =
355 clang::FieldDecl::Create(Ctx,
356 RD,
357 clang::SourceLocation(),
358 clang::SourceLocation(),
359 PVD->getIdentifier(),
360 QT->getPointeeType(),
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700361 nullptr,
362 /* BitWidth = */ nullptr,
Shih-wei Liao1688a3c2011-06-22 05:21:27 -0700363 /* Mutable = */ false,
Shih-wei Liao43730fe2012-08-02 23:06:18 -0700364 /* HasInit = */ clang::ICIS_NoInit);
Stephen Hines593a8942011-05-10 15:29:50 -0700365 RD->addDecl(FD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700366 RD->completeDefinition();
367
368 // Create an export type iff we have a valid usrData type
369 clang::QualType T = Ctx.getTagDeclType(RD);
370 slangAssert(!T.isNull());
371
Stephen Hines13fad852015-11-23 19:32:14 -0800372 RSExportType *ET =
373 RSExportType::Create(Context, T.getTypePtr(), LegacyKernelArgument);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700374
David Gross50ff2632017-07-06 14:12:46 -0700375 if (ET) {
376 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
377 "Parameter packet must be a record");
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700378
David Gross50ff2632017-07-06 14:12:46 -0700379 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
380 } else {
381 TypeExportError = true;
382 }
Stephen Hines593a8942011-05-10 15:29:50 -0700383 }
384 }
Stephen Hines593a8942011-05-10 15:29:50 -0700385
Stephen Hinesa088faa2015-06-22 19:46:56 -0700386 if (FE->hasIns()) {
Chris Wailesc9454af2014-06-13 17:25:40 -0700387 for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
388 const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
Stephen Hines13fad852015-11-23 19:32:14 -0800389 ExportKind EK = (FE->mIsKernelStyle ? NotLegacyKernelArgument :
390 LegacyKernelArgument);
391 RSExportType *InExportType = RSExportType::Create(Context, T, EK);
Chris Wailesc9454af2014-06-13 17:25:40 -0700392
Stephen Hinesa088faa2015-06-22 19:46:56 -0700393 // It is not an error if we don't export an input type for legacy
Stephen Hines13fad852015-11-23 19:32:14 -0800394 // kernel arguments. This can happen in the case of a void pointer.
David Grossd80e58b2017-07-24 11:41:12 -0700395 // See ReflectionState::addForEachIn().
Stephen Hinesa088faa2015-06-22 19:46:56 -0700396 if (FE->mIsKernelStyle && !InExportType) {
397 TypeExportError = true;
Chris Wailesc9454af2014-06-13 17:25:40 -0700398 }
399
400 FE->mInTypes.push_back(InExportType);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700401 }
Stephen Hines593a8942011-05-10 15:29:50 -0700402 }
Stephen Hines5baf6322011-04-25 17:21:15 -0700403
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800404 if (FE->mIsKernelStyle && FE->mHasReturnType) {
Stephen Hinesa088faa2015-06-22 19:46:56 -0700405 const clang::Type *ReturnType = FE->mResultType.getTypePtr();
Stephen Hines13fad852015-11-23 19:32:14 -0800406 FE->mOutType = RSExportType::Create(Context, ReturnType,
407 NotLegacyKernelArgument);
Stephen Hinesa088faa2015-06-22 19:46:56 -0700408 TypeExportError |= !FE->mOutType;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700409 } else if (FE->mOut) {
Stephen Hinesa088faa2015-06-22 19:46:56 -0700410 const clang::Type *OutType =
411 FE->mOut->getType().getCanonicalType().getTypePtr();
Stephen Hines13fad852015-11-23 19:32:14 -0800412 FE->mOutType = RSExportType::Create(Context, OutType, LegacyKernelArgument);
Stephen Hinesa088faa2015-06-22 19:46:56 -0700413 // It is not an error if we don't export an output type.
414 // This can happen in the case of a void pointer.
415 }
416
417 if (TypeExportError) {
418 slangAssert(Context->getDiagnostics()->hasErrorOccurred() &&
419 "Error exporting type but no diagnostic message issued!");
420 return nullptr;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700421 }
422
423 return FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700424}
425
Stephen Hinesc17e1982012-02-22 12:30:45 -0800426RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
427 slangAssert(Context);
428 llvm::StringRef Name = "root";
David Gross63e61082017-07-13 14:17:29 -0700429 RSExportForEach *FE = new RSExportForEach(Context, Name, clang::SourceLocation());
Stephen Hinesc17e1982012-02-22 12:30:45 -0800430 FE->mDummyRoot = true;
431 return FE;
432}
433
Chris Wailesc9454af2014-06-13 17:25:40 -0700434bool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
Chris Wailesc9454af2014-06-13 17:25:40 -0700435 const clang::FunctionDecl *FD) {
Yang Nifb40ee22015-10-13 20:34:06 +0000436 if (!FD) {
437 return false;
438 }
Stephen Hines089cde32012-12-07 19:19:10 -0800439
Matt Walac0c5dd82015-07-23 17:29:37 -0700440 // Anything tagged as a kernel("") is definitely used with ForEach.
Pirama Arumuga Nainarb6a14352016-07-26 11:39:47 -0700441 if (FD->hasAttr<clang::RenderScriptKernelAttr>()) {
442 return true;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700443 }
444
Matt Walaeae0b7a2015-06-16 14:06:25 -0700445 if (RSSpecialFunc::isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700446 return false;
447 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700448
Stephen Hines7b51b552012-02-16 00:12:38 -0800449 // Check if first parameter is a pointer (which is required for ForEach).
450 unsigned int numParams = FD->getNumParams();
451
452 if (numParams > 0) {
453 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
454 clang::QualType QT = PVD->getType().getCanonicalType();
455
456 if (QT->isPointerType()) {
457 return true;
458 }
459
460 // Any non-graphics root() is automatically a ForEach candidate.
461 // At this point, however, we know that it is not going to be a valid
462 // compute root() function (due to not having a pointer parameter). We
463 // still want to return true here, so that we can issue appropriate
464 // diagnostics.
465 if (isRootRSFunc(FD)) {
466 return true;
467 }
468 }
469
470 return false;
Stephen Hines593a8942011-05-10 15:29:50 -0700471}
472
Yang Ni19467492015-10-27 15:24:41 -0700473unsigned RSExportForEach::getNumInputs(unsigned int targetAPI,
474 const clang::FunctionDecl *FD) {
475 unsigned numInputs = 0;
Pirama Arumuga Nainarb6a14352016-07-26 11:39:47 -0700476 for (const clang::ParmVarDecl* param : FD->parameters()) {
David Gross46e146e2015-11-11 15:14:01 -0800477 if (!isSpecialKernelParameter(param->getName())) {
Yang Ni19467492015-10-27 15:24:41 -0700478 numInputs++;
479 }
480 }
481
482 return numInputs;
483}
484
Stephen Hines5baf6322011-04-25 17:21:15 -0700485} // namespace slang