blob: 8baac34bec776a385387e1cb452e1845f882e5e6 [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"
Stephen Hines12580dc2011-10-10 17:44:10 -070034#include "slang_version.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070035
David Gross18c50eb2015-01-30 11:39:22 -080036namespace {
37
David Grosscd7d3122015-03-13 15:11:44 -070038const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
39
David Gross18c50eb2015-01-30 11:39:22 -080040enum SpecialParameterKind {
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070041 SPK_LOCATION, // 'int' or 'unsigned int'
42 SPK_CONTEXT, // rs_kernel_context
David Gross18c50eb2015-01-30 11:39:22 -080043};
44
45struct SpecialParameter {
46 const char *name;
47 bcinfo::MetadataSignatureBitval bitval;
48 SpecialParameterKind kind;
49 SlangTargetAPI minAPI;
50};
51
52// Table entries are in the order parameters must occur in a kernel parameter list.
53const SpecialParameter specialParameterTable[] = {
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070054 { "context", bcinfo::MD_SIG_Ctxt, SPK_CONTEXT, SLANG_M_TARGET_API },
55 { "x", bcinfo::MD_SIG_X, SPK_LOCATION, SLANG_MINIMUM_TARGET_API },
56 { "y", bcinfo::MD_SIG_Y, SPK_LOCATION, SLANG_MINIMUM_TARGET_API },
57 { "z", bcinfo::MD_SIG_Z, SPK_LOCATION, SLANG_M_TARGET_API },
58 { nullptr, bcinfo::MD_SIG_None, SPK_LOCATION, SLANG_MINIMUM_TARGET_API }, // marks end of table
David Gross18c50eb2015-01-30 11:39:22 -080059};
60
61// If the specified name matches the name of an entry in
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070062// specialParameterTable, return the corresponding table index.
63// Return -1 if not found.
David Gross18c50eb2015-01-30 11:39:22 -080064int lookupSpecialParameter(const llvm::StringRef name) {
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070065 for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
66 if (name.equals(specialParameterTable[i].name)) {
David Gross18c50eb2015-01-30 11:39:22 -080067 return i;
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070068 }
69 }
70
David Gross18c50eb2015-01-30 11:39:22 -080071 return -1;
72}
73
74// Return a comma-separated list of names in specialParameterTable
75// that are available at the specified API level.
76std::string listSpecialParameters(unsigned int api) {
77 std::string ret;
78 bool first = true;
79 for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
80 if (specialParameterTable[i].minAPI > api)
81 continue;
82 if (first)
83 first = false;
84 else
85 ret += ", ";
86 ret += "'";
87 ret += specialParameterTable[i].name;
88 ret += "'";
89 }
90 return ret;
91}
92
Matt Walaeae0b7a2015-06-16 14:06:25 -070093bool isRootRSFunc(const clang::FunctionDecl *FD) {
94 if (!FD) {
95 return false;
96 }
97 return FD->getName().equals("root");
David Gross7cc68762015-03-11 14:29:24 -070098}
David Gross18c50eb2015-01-30 11:39:22 -080099
Matt Walaeae0b7a2015-06-16 14:06:25 -0700100} // end anonymous namespace
101
Stephen Hines5baf6322011-04-25 17:21:15 -0700102namespace slang {
103
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700104// This function takes care of additional validation and construction of
105// parameters related to forEach_* reflection.
106bool RSExportForEach::validateAndConstructParams(
107 RSContext *Context, const clang::FunctionDecl *FD) {
108 slangAssert(Context && FD);
109 bool valid = true;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700110
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700111 numParams = FD->getNumParams();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700112
Stephen Hines7b51b552012-02-16 00:12:38 -0800113 if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000114 // Before JellyBean, we allowed only one kernel per file. It must be called "root".
Stephen Hines7b51b552012-02-16 00:12:38 -0800115 if (!isRootRSFunc(FD)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800116 Context->ReportError(FD->getLocation(),
117 "Non-root compute kernel %0() is "
118 "not supported in SDK levels %1-%2")
119 << FD->getName() << SLANG_MINIMUM_TARGET_API
120 << (SLANG_JB_TARGET_API - 1);
Stephen Hines7b51b552012-02-16 00:12:38 -0800121 return false;
122 }
123 }
124
Tim Murrayee4016d2014-04-10 15:49:08 -0700125 mResultType = FD->getReturnType().getCanonicalType();
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800126 // Compute kernel functions are defined differently when the
127 // "__attribute__((kernel))" is set.
Stephen Hines9ca96e72012-09-13 16:57:06 -0700128 if (FD->hasAttr<clang::KernelAttr>()) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800129 valid |= validateAndConstructKernelParams(Context, FD);
130 } else {
131 valid |= validateAndConstructOldStyleParams(Context, FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700132 }
Chris Wailesc9454af2014-06-13 17:25:40 -0700133
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800134 valid |= setSignatureMetadata(Context, FD);
135 return valid;
136}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700137
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800138bool RSExportForEach::validateAndConstructOldStyleParams(
139 RSContext *Context, const clang::FunctionDecl *FD) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800140 slangAssert(Context && FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700141 // If numParams is 0, we already marked this as a graphics root().
142 slangAssert(numParams > 0);
143
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800144 bool valid = true;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800145
146 // Compute kernel functions of this style are required to return a void type.
147 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700148 if (mResultType != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800149 Context->ReportError(FD->getLocation(),
150 "Compute kernel %0() is required to return a "
151 "void type")
152 << FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700153 valid = false;
154 }
155
156 // Validate remaining parameter types
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700157
David Gross18c50eb2015-01-30 11:39:22 -0800158 size_t IndexOfFirstSpecialParameter = numParams;
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700159 valid |= processSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700160
David Gross18c50eb2015-01-30 11:39:22 -0800161 // Validate the non-special parameters, which should all be found before the
162 // first special parameter.
163 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800164 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
165 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700166
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800167 if (!QT->isPointerType()) {
168 Context->ReportError(PVD->getLocation(),
169 "Compute kernel %0() cannot have non-pointer "
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700170 "parameters besides special parameters (%1). Parameter '%2' is "
David Gross18c50eb2015-01-30 11:39:22 -0800171 "of type: '%3'")
172 << FD->getName() << listSpecialParameters(Context->getTargetAPI())
173 << PVD->getName() << PVD->getType().getAsString();
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800174 valid = false;
175 continue;
176 }
177
178 // The only non-const pointer should be out.
179 if (!QT->getPointeeType().isConstQualified()) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700180 if (mOut == nullptr) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800181 mOut = PVD;
182 } else {
183 Context->ReportError(PVD->getLocation(),
184 "Compute kernel %0() can only have one non-const "
185 "pointer parameter. Parameters '%1' and '%2' are "
186 "both non-const.")
187 << FD->getName() << mOut->getName() << PVD->getName();
188 valid = false;
189 }
190 } else {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700191 if (mIns.empty() && mOut == nullptr) {
Chris Wailesc9454af2014-06-13 17:25:40 -0700192 mIns.push_back(PVD);
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700193 } else if (mUsrData == nullptr) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800194 mUsrData = PVD;
195 } else {
196 Context->ReportError(
197 PVD->getLocation(),
198 "Unexpected parameter '%0' for compute kernel %1()")
199 << PVD->getName() << FD->getName();
200 valid = false;
201 }
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700202 }
203 }
204
Chris Wailesc9454af2014-06-13 17:25:40 -0700205 if (mIns.empty() && !mOut) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800206 Context->ReportError(FD->getLocation(),
207 "Compute kernel %0() must have at least one "
208 "parameter for in or out")
209 << FD->getName();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700210 valid = false;
211 }
212
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700213 return valid;
214}
215
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800216bool RSExportForEach::validateAndConstructKernelParams(
217 RSContext *Context, const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700218 slangAssert(Context && FD);
219 bool valid = true;
220 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700221
222 if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800223 Context->ReportError(FD->getLocation(),
224 "Compute kernel %0() targeting SDK levels "
225 "%1-%2 may not use pass-by-value with "
226 "__attribute__((kernel))")
227 << FD->getName() << SLANG_MINIMUM_TARGET_API
228 << (SLANG_JB_MR1_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700229 return false;
230 }
231
232 // Denote that we are indeed a pass-by-value kernel.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800233 mIsKernelStyle = true;
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800234 mHasReturnType = (mResultType != C.VoidTy);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700235
236 if (mResultType->isPointerType()) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800237 Context->ReportError(
238 FD->getTypeSpecStartLoc(),
239 "Compute kernel %0() cannot return a pointer type: '%1'")
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800240 << FD->getName() << mResultType.getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700241 valid = false;
242 }
243
244 // Validate remaining parameter types
Stephen Hines9ca96e72012-09-13 16:57:06 -0700245
David Gross18c50eb2015-01-30 11:39:22 -0800246 size_t IndexOfFirstSpecialParameter = numParams;
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700247 valid |= processSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700248
David Gross18c50eb2015-01-30 11:39:22 -0800249 // Validate the non-special parameters, which should all be found before the
250 // first special.
251 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800252 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
Chris Wailesc9454af2014-06-13 17:25:40 -0700253
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700254 if (Context->getTargetAPI() >= SLANG_M_TARGET_API || i == 0) {
David Grosscd7d3122015-03-13 15:11:44 -0700255 if (i >= RS_KERNEL_INPUT_LIMIT) {
256 Context->ReportError(PVD->getLocation(),
257 "Invalid parameter '%0' for compute kernel %1(). "
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700258 "Kernels targeting SDK levels %2+ may not use "
259 "more than %3 input parameters.") << PVD->getName() <<
260 FD->getName() << SLANG_M_TARGET_API <<
261 int(RS_KERNEL_INPUT_LIMIT);
David Grosscd7d3122015-03-13 15:11:44 -0700262
263 } else {
264 mIns.push_back(PVD);
265 }
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800266 } else {
267 Context->ReportError(PVD->getLocation(),
Chris Wailesc9454af2014-06-13 17:25:40 -0700268 "Invalid parameter '%0' for compute kernel %1(). "
269 "Kernels targeting SDK levels %2-%3 may not use "
270 "multiple input parameters.") << PVD->getName() <<
271 FD->getName() << SLANG_MINIMUM_TARGET_API <<
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700272 (SLANG_M_TARGET_API - 1);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800273 valid = false;
274 }
275 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700276 if (QT->isPointerType()) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800277 Context->ReportError(PVD->getLocation(),
278 "Compute kernel %0() cannot have "
279 "parameter '%1' of pointer type: '%2'")
280 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700281 valid = false;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700282 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700283 }
284
285 // Check that we have at least one allocation to use for dimensions.
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700286 if (valid && mIns.empty() && !mHasReturnType && Context->getTargetAPI() < SLANG_M_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800287 Context->ReportError(FD->getLocation(),
David Grossfb78d4c2015-03-31 13:56:05 -0700288 "Compute kernel %0() targeting SDK levels "
289 "%1-%2 must have at least one "
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800290 "input parameter or a non-void return "
291 "type")
David Grossfb78d4c2015-03-31 13:56:05 -0700292 << FD->getName() << SLANG_MINIMUM_TARGET_API
Stephen Hinesbd0a7dd2015-07-01 19:24:00 -0700293 << (SLANG_M_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700294 valid = false;
295 }
296
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800297 return valid;
298}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700299
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700300// Process the optional special parameters:
301// - Sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or
302// FD->getNumParams() if none are found.
303// - Sets mSpecialParameterSignatureMetadata for the found special parameters.
304// Returns true if no errors.
305bool RSExportForEach::processSpecialParameters(
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800306 RSContext *Context, const clang::FunctionDecl *FD,
David Gross18c50eb2015-01-30 11:39:22 -0800307 size_t *IndexOfFirstSpecialParameter) {
308 slangAssert(IndexOfFirstSpecialParameter != nullptr);
309 slangAssert(mSpecialParameterSignatureMetadata == 0);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800310 clang::ASTContext &C = Context->getASTContext();
311
David Gross18c50eb2015-01-30 11:39:22 -0800312 // Find all special parameters if present.
313 int LastSpecialParameterIdx = -1; // index into specialParameterTable
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700314 int FirstLocationSpecialParameterIdx = -1; // index into specialParameterTable
315 clang::QualType FirstLocationSpecialParameterType;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800316 size_t NumParams = FD->getNumParams();
David Gross18c50eb2015-01-30 11:39:22 -0800317 *IndexOfFirstSpecialParameter = NumParams;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800318 bool valid = true;
319 for (size_t i = 0; i < NumParams; i++) {
320 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700321 const llvm::StringRef ParamName = PVD->getName();
322 const clang::QualType Type = PVD->getType();
323 const clang::QualType QT = Type.getCanonicalType();
324 const clang::QualType UT = QT.getUnqualifiedType();
David Gross18c50eb2015-01-30 11:39:22 -0800325 int SpecialParameterIdx = lookupSpecialParameter(ParamName);
David Gross18c50eb2015-01-30 11:39:22 -0800326
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700327 static const char KernelContextUnqualifiedTypeName[] =
328 "const struct rs_kernel_context_t *";
329 static const char KernelContextTypeName[] = "rs_kernel_context";
David Gross18c50eb2015-01-30 11:39:22 -0800330
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700331 // If the type is rs_context, it should have been named "context" and classified
332 // as a special parameter.
333 if (SpecialParameterIdx < 0 && UT.getAsString() == KernelContextUnqualifiedTypeName) {
334 Context->ReportError(
335 PVD->getLocation(),
336 "The special parameter of type '%0' must be called "
337 "'context' instead of '%1'.")
338 << KernelContextTypeName << ParamName;
339 SpecialParameterIdx = lookupSpecialParameter("context");
340 }
David Gross18c50eb2015-01-30 11:39:22 -0800341
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700342 // If it's not a special parameter, check that it appears before any special
343 // parameter.
344 if (SpecialParameterIdx < 0) {
David Gross18c50eb2015-01-30 11:39:22 -0800345 if (*IndexOfFirstSpecialParameter < NumParams) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800346 Context->ReportError(PVD->getLocation(),
347 "In compute kernel %0(), parameter '%1' cannot "
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700348 "appear after any of the special parameters (%2).")
David Gross18c50eb2015-01-30 11:39:22 -0800349 << FD->getName() << ParamName << listSpecialParameters(Context->getTargetAPI());
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800350 valid = false;
351 }
352 continue;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700353 }
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700354
355 const SpecialParameter &SP = specialParameterTable[SpecialParameterIdx];
356
357 // Verify that this special parameter is OK for the current API level.
358 if (Context->getTargetAPI() < SP.minAPI) {
359 Context->ReportError(PVD->getLocation(),
360 "Compute kernel %0() targeting SDK levels "
361 "%1-%2 may not use special parameter '%3'.")
362 << FD->getName() << SLANG_MINIMUM_TARGET_API << (SP.minAPI - 1)
363 << SP.name;
364 valid = false;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800365 }
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700366
367 // Check that the order of the special parameters is correct.
368 if (SpecialParameterIdx < LastSpecialParameterIdx) {
369 Context->ReportError(
370 PVD->getLocation(),
371 "In compute kernel %0(), special parameter '%1' must "
372 "be defined before special parameter '%2'.")
373 << FD->getName() << SP.name
374 << specialParameterTable[LastSpecialParameterIdx].name;
375 valid = false;
376 }
377
378 // Validate the data type of the special parameter.
379 switch (SP.kind) {
380 case SPK_LOCATION: {
381 // Location special parameters can only be int or uint.
382 if (UT != C.UnsignedIntTy && UT != C.IntTy) {
383 Context->ReportError(PVD->getLocation(),
384 "Special parameter '%0' must be of type 'int' or "
385 "'unsigned int'. It is of type '%1'.")
386 << ParamName << Type.getAsString();
387 valid = false;
388 }
389
390 // Ensure that all location special parameters have the same type.
391 if (FirstLocationSpecialParameterIdx >= 0) {
392 if (Type != FirstLocationSpecialParameterType) {
393 Context->ReportError(
394 PVD->getLocation(),
395 "Special parameters '%0' and '%1' must be of the same type. "
396 "'%0' is of type '%2' while '%1' is of type '%3'.")
397 << specialParameterTable[FirstLocationSpecialParameterIdx].name
398 << SP.name << FirstLocationSpecialParameterType.getAsString()
399 << Type.getAsString();
400 valid = false;
401 }
402 } else {
403 FirstLocationSpecialParameterIdx = SpecialParameterIdx;
404 FirstLocationSpecialParameterType = Type;
405 }
406 } break;
407 case SPK_CONTEXT: {
408 // Check that variables named "context" are of type rs_context.
409 if (UT.getAsString() != KernelContextUnqualifiedTypeName) {
410 Context->ReportError(PVD->getLocation(),
411 "Special parameter '%0' must be of type '%1'. "
412 "It is of type '%2'.")
413 << ParamName << KernelContextTypeName
414 << Type.getAsString();
415 valid = false;
416 }
417 } break;
418 default:
419 slangAssert(!"Unexpected special parameter type");
420 }
421
422 // We should not be invoked if two parameters of the same name are present.
423 slangAssert(!(mSpecialParameterSignatureMetadata & SP.bitval));
424 mSpecialParameterSignatureMetadata |= SP.bitval;
425
426 LastSpecialParameterIdx = SpecialParameterIdx;
David Gross18c50eb2015-01-30 11:39:22 -0800427 // If this is the first time we find a special parameter, save it.
428 if (*IndexOfFirstSpecialParameter >= NumParams) {
429 *IndexOfFirstSpecialParameter = i;
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000430 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700431 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700432 return valid;
433}
434
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800435bool RSExportForEach::setSignatureMetadata(RSContext *Context,
436 const clang::FunctionDecl *FD) {
437 mSignatureMetadata = 0;
438 bool valid = true;
439
440 if (mIsKernelStyle) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700441 slangAssert(mOut == nullptr);
442 slangAssert(mUsrData == nullptr);
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800443 } else {
444 slangAssert(!mHasReturnType);
445 }
446
447 // Set up the bitwise metadata encoding for runtime argument passing.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800448 const bool HasOut = mOut || mHasReturnType;
David Gross18c50eb2015-01-30 11:39:22 -0800449 mSignatureMetadata |= (hasIns() ? bcinfo::MD_SIG_In : 0);
450 mSignatureMetadata |= (HasOut ? bcinfo::MD_SIG_Out : 0);
451 mSignatureMetadata |= (mUsrData ? bcinfo::MD_SIG_Usr : 0);
452 mSignatureMetadata |= (mIsKernelStyle ? bcinfo::MD_SIG_Kernel : 0); // pass-by-value
453 mSignatureMetadata |= mSpecialParameterSignatureMetadata;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800454
455 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
456 // APIs before ICS cannot skip between parameters. It is ok, however, for
457 // them to omit further parameters (i.e. skipping X is ok if you skip Y).
David Gross18c50eb2015-01-30 11:39:22 -0800458 if (mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
459 bcinfo::MD_SIG_X | bcinfo::MD_SIG_Y) &&
460 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
461 bcinfo::MD_SIG_X) &&
462 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr) &&
463 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out) &&
464 mSignatureMetadata != (bcinfo::MD_SIG_In)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800465 Context->ReportError(FD->getLocation(),
466 "Compute kernel %0() targeting SDK levels "
467 "%1-%2 may not skip parameters")
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800468 << FD->getName() << SLANG_MINIMUM_TARGET_API
469 << (SLANG_ICS_TARGET_API - 1);
470 valid = false;
471 }
472 }
473 return valid;
474}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700475
Stephen Hines593a8942011-05-10 15:29:50 -0700476RSExportForEach *RSExportForEach::Create(RSContext *Context,
477 const clang::FunctionDecl *FD) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700478 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700479 llvm::StringRef Name = FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700480 RSExportForEach *FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700481
482 slangAssert(!Name.empty() && "Function must have a name");
483
Stephen Hinesc17e1982012-02-22 12:30:45 -0800484 FE = new RSExportForEach(Context, Name);
Stephen Hines593a8942011-05-10 15:29:50 -0700485
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700486 if (!FE->validateAndConstructParams(Context, FD)) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700487 return nullptr;
Stephen Hines593a8942011-05-10 15:29:50 -0700488 }
489
490 clang::ASTContext &Ctx = Context->getASTContext();
491
Jean-Luc Brouilleteca05342014-05-15 12:44:21 -0700492 std::string Id = CreateDummyName("helper_foreach_param", FE->getName());
Stephen Hines593a8942011-05-10 15:29:50 -0700493
494 // Extract the usrData parameter (if we have one)
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700495 if (FE->mUsrData) {
496 const clang::ParmVarDecl *PVD = FE->mUsrData;
Stephen Hines593a8942011-05-10 15:29:50 -0700497 clang::QualType QT = PVD->getType().getCanonicalType();
498 slangAssert(QT->isPointerType() &&
499 QT->getPointeeType().isConstQualified());
500
501 const clang::ASTContext &C = Context->getASTContext();
502 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
503 C.VoidTy) {
504 // In the case of using const void*, we can't reflect an appopriate
505 // Java type, so we fall back to just reflecting the ain/aout parameters
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700506 FE->mUsrData = nullptr;
Stephen Hines593a8942011-05-10 15:29:50 -0700507 } else {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700508 clang::RecordDecl *RD =
509 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
510 Ctx.getTranslationUnitDecl(),
511 clang::SourceLocation(),
512 clang::SourceLocation(),
513 &Ctx.Idents.get(Id));
514
Stephen Hines593a8942011-05-10 15:29:50 -0700515 clang::FieldDecl *FD =
516 clang::FieldDecl::Create(Ctx,
517 RD,
518 clang::SourceLocation(),
519 clang::SourceLocation(),
520 PVD->getIdentifier(),
521 QT->getPointeeType(),
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700522 nullptr,
523 /* BitWidth = */ nullptr,
Shih-wei Liao1688a3c2011-06-22 05:21:27 -0700524 /* Mutable = */ false,
Shih-wei Liao43730fe2012-08-02 23:06:18 -0700525 /* HasInit = */ clang::ICIS_NoInit);
Stephen Hines593a8942011-05-10 15:29:50 -0700526 RD->addDecl(FD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700527 RD->completeDefinition();
528
529 // Create an export type iff we have a valid usrData type
530 clang::QualType T = Ctx.getTagDeclType(RD);
531 slangAssert(!T.isNull());
532
533 RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
534
Stephen Hinesab94bcc2015-06-11 17:00:04 -0700535 slangAssert(ET && "Failed to export a kernel");
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700536
537 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
538 "Parameter packet must be a record");
539
540 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
Stephen Hines593a8942011-05-10 15:29:50 -0700541 }
542 }
Stephen Hines593a8942011-05-10 15:29:50 -0700543
Stephen Hinesa088faa2015-06-22 19:46:56 -0700544 // Construct type information about inputs and outputs. Return null when
545 // there is an error exporting types.
Stephen Hinesd4639562015-06-22 19:45:03 -0700546
Stephen Hinesa088faa2015-06-22 19:46:56 -0700547 bool TypeExportError = false;
548
549 if (FE->hasIns()) {
Chris Wailesc9454af2014-06-13 17:25:40 -0700550 for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
551 const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
552 RSExportType *InExportType = RSExportType::Create(Context, T);
553
Stephen Hinesa088faa2015-06-22 19:46:56 -0700554 // It is not an error if we don't export an input type for legacy
555 // kernels. This can happen in the case of a void pointer.
556 if (FE->mIsKernelStyle && !InExportType) {
557 TypeExportError = true;
Chris Wailesc9454af2014-06-13 17:25:40 -0700558 }
559
560 FE->mInTypes.push_back(InExportType);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700561 }
Stephen Hines593a8942011-05-10 15:29:50 -0700562 }
Stephen Hines5baf6322011-04-25 17:21:15 -0700563
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800564 if (FE->mIsKernelStyle && FE->mHasReturnType) {
Stephen Hinesa088faa2015-06-22 19:46:56 -0700565 const clang::Type *ReturnType = FE->mResultType.getTypePtr();
566 FE->mOutType = RSExportType::Create(Context, ReturnType);
567 TypeExportError |= !FE->mOutType;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700568 } else if (FE->mOut) {
Stephen Hinesa088faa2015-06-22 19:46:56 -0700569 const clang::Type *OutType =
570 FE->mOut->getType().getCanonicalType().getTypePtr();
571 FE->mOutType = RSExportType::Create(Context, OutType);
572 // It is not an error if we don't export an output type.
573 // This can happen in the case of a void pointer.
574 }
575
576 if (TypeExportError) {
577 slangAssert(Context->getDiagnostics()->hasErrorOccurred() &&
578 "Error exporting type but no diagnostic message issued!");
579 return nullptr;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700580 }
581
582 return FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700583}
584
Stephen Hinesc17e1982012-02-22 12:30:45 -0800585RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
586 slangAssert(Context);
587 llvm::StringRef Name = "root";
588 RSExportForEach *FE = new RSExportForEach(Context, Name);
589 FE->mDummyRoot = true;
590 return FE;
591}
592
Chris Wailesc9454af2014-06-13 17:25:40 -0700593bool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
Chris Wailesc9454af2014-06-13 17:25:40 -0700594 const clang::FunctionDecl *FD) {
Yang Nifb40ee22015-10-13 20:34:06 +0000595 if (!FD) {
596 return false;
597 }
Stephen Hines089cde32012-12-07 19:19:10 -0800598
Matt Walac0c5dd82015-07-23 17:29:37 -0700599 // Anything tagged as a kernel("") is definitely used with ForEach.
600 if (auto *Kernel = FD->getAttr<clang::KernelAttr>()) {
601 return Kernel->getKernelKind().empty();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700602 }
603
Matt Walaeae0b7a2015-06-16 14:06:25 -0700604 if (RSSpecialFunc::isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700605 return false;
606 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700607
Stephen Hines7b51b552012-02-16 00:12:38 -0800608 // Check if first parameter is a pointer (which is required for ForEach).
609 unsigned int numParams = FD->getNumParams();
610
611 if (numParams > 0) {
612 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
613 clang::QualType QT = PVD->getType().getCanonicalType();
614
615 if (QT->isPointerType()) {
616 return true;
617 }
618
619 // Any non-graphics root() is automatically a ForEach candidate.
620 // At this point, however, we know that it is not going to be a valid
621 // compute root() function (due to not having a pointer parameter). We
622 // still want to return true here, so that we can issue appropriate
623 // diagnostics.
624 if (isRootRSFunc(FD)) {
625 return true;
626 }
627 }
628
629 return false;
Stephen Hines593a8942011-05-10 15:29:50 -0700630}
631
Stephen Hines5baf6322011-04-25 17:21:15 -0700632} // namespace slang