blob: d539e132686f9109558292991000c76b277ef68d [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"
Stephen Hines12580dc2011-10-10 17:44:10 -070033#include "slang_version.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070034
David Gross18c50eb2015-01-30 11:39:22 -080035namespace {
36
David Grosscd7d3122015-03-13 15:11:44 -070037const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
38
David Gross18c50eb2015-01-30 11:39:22 -080039enum SpecialParameterKind {
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070040 SPK_LOCATION, // 'int' or 'unsigned int'
41 SPK_CONTEXT, // rs_kernel_context
David Gross18c50eb2015-01-30 11:39:22 -080042};
43
44struct SpecialParameter {
45 const char *name;
46 bcinfo::MetadataSignatureBitval bitval;
47 SpecialParameterKind kind;
48 SlangTargetAPI minAPI;
49};
50
51// Table entries are in the order parameters must occur in a kernel parameter list.
52const SpecialParameter specialParameterTable[] = {
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070053 { "context", bcinfo::MD_SIG_Ctxt, SPK_CONTEXT, SLANG_M_TARGET_API },
54 { "x", bcinfo::MD_SIG_X, SPK_LOCATION, SLANG_MINIMUM_TARGET_API },
55 { "y", bcinfo::MD_SIG_Y, SPK_LOCATION, SLANG_MINIMUM_TARGET_API },
56 { "z", bcinfo::MD_SIG_Z, SPK_LOCATION, SLANG_M_TARGET_API },
57 { nullptr, bcinfo::MD_SIG_None, SPK_LOCATION, SLANG_MINIMUM_TARGET_API }, // marks end of table
David Gross18c50eb2015-01-30 11:39:22 -080058};
59
60// If the specified name matches the name of an entry in
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070061// specialParameterTable, return the corresponding table index.
62// Return -1 if not found.
David Gross18c50eb2015-01-30 11:39:22 -080063int lookupSpecialParameter(const llvm::StringRef name) {
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070064 for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
65 if (name.equals(specialParameterTable[i].name)) {
David Gross18c50eb2015-01-30 11:39:22 -080066 return i;
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -070067 }
68 }
69
David Gross18c50eb2015-01-30 11:39:22 -080070 return -1;
71}
72
73// Return a comma-separated list of names in specialParameterTable
74// that are available at the specified API level.
75std::string listSpecialParameters(unsigned int api) {
76 std::string ret;
77 bool first = true;
78 for (int i = 0; specialParameterTable[i].name != nullptr; ++i) {
79 if (specialParameterTable[i].minAPI > api)
80 continue;
81 if (first)
82 first = false;
83 else
84 ret += ", ";
85 ret += "'";
86 ret += specialParameterTable[i].name;
87 ret += "'";
88 }
89 return ret;
90}
91
David Gross7cc68762015-03-11 14:29:24 -070092}
David Gross18c50eb2015-01-30 11:39:22 -080093
Stephen Hines5baf6322011-04-25 17:21:15 -070094namespace slang {
95
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070096// This function takes care of additional validation and construction of
97// parameters related to forEach_* reflection.
98bool RSExportForEach::validateAndConstructParams(
99 RSContext *Context, const clang::FunctionDecl *FD) {
100 slangAssert(Context && FD);
101 bool valid = true;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700102
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700103 numParams = FD->getNumParams();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700104
Stephen Hines7b51b552012-02-16 00:12:38 -0800105 if (Context->getTargetAPI() < SLANG_JB_TARGET_API) {
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000106 // Before JellyBean, we allowed only one kernel per file. It must be called "root".
Stephen Hines7b51b552012-02-16 00:12:38 -0800107 if (!isRootRSFunc(FD)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800108 Context->ReportError(FD->getLocation(),
109 "Non-root compute kernel %0() is "
110 "not supported in SDK levels %1-%2")
111 << FD->getName() << SLANG_MINIMUM_TARGET_API
112 << (SLANG_JB_TARGET_API - 1);
Stephen Hines7b51b552012-02-16 00:12:38 -0800113 return false;
114 }
115 }
116
Tim Murrayee4016d2014-04-10 15:49:08 -0700117 mResultType = FD->getReturnType().getCanonicalType();
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800118 // Compute kernel functions are defined differently when the
119 // "__attribute__((kernel))" is set.
Stephen Hines9ca96e72012-09-13 16:57:06 -0700120 if (FD->hasAttr<clang::KernelAttr>()) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800121 valid |= validateAndConstructKernelParams(Context, FD);
122 } else {
123 valid |= validateAndConstructOldStyleParams(Context, FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700124 }
Chris Wailesc9454af2014-06-13 17:25:40 -0700125
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800126 valid |= setSignatureMetadata(Context, FD);
127 return valid;
128}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700129
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800130bool RSExportForEach::validateAndConstructOldStyleParams(
131 RSContext *Context, const clang::FunctionDecl *FD) {
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800132 slangAssert(Context && FD);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700133 // If numParams is 0, we already marked this as a graphics root().
134 slangAssert(numParams > 0);
135
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800136 bool valid = true;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800137
138 // Compute kernel functions of this style are required to return a void type.
139 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700140 if (mResultType != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800141 Context->ReportError(FD->getLocation(),
142 "Compute kernel %0() is required to return a "
143 "void type")
144 << FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700145 valid = false;
146 }
147
148 // Validate remaining parameter types
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700149
David Gross18c50eb2015-01-30 11:39:22 -0800150 size_t IndexOfFirstSpecialParameter = numParams;
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700151 valid |= processSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700152
David Gross18c50eb2015-01-30 11:39:22 -0800153 // Validate the non-special parameters, which should all be found before the
154 // first special parameter.
155 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800156 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
157 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700158
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800159 if (!QT->isPointerType()) {
160 Context->ReportError(PVD->getLocation(),
161 "Compute kernel %0() cannot have non-pointer "
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700162 "parameters besides special parameters (%1). Parameter '%2' is "
David Gross18c50eb2015-01-30 11:39:22 -0800163 "of type: '%3'")
164 << FD->getName() << listSpecialParameters(Context->getTargetAPI())
165 << PVD->getName() << PVD->getType().getAsString();
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800166 valid = false;
167 continue;
168 }
169
170 // The only non-const pointer should be out.
171 if (!QT->getPointeeType().isConstQualified()) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700172 if (mOut == nullptr) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800173 mOut = PVD;
174 } else {
175 Context->ReportError(PVD->getLocation(),
176 "Compute kernel %0() can only have one non-const "
177 "pointer parameter. Parameters '%1' and '%2' are "
178 "both non-const.")
179 << FD->getName() << mOut->getName() << PVD->getName();
180 valid = false;
181 }
182 } else {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700183 if (mIns.empty() && mOut == nullptr) {
Chris Wailesc9454af2014-06-13 17:25:40 -0700184 mIns.push_back(PVD);
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700185 } else if (mUsrData == nullptr) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800186 mUsrData = PVD;
187 } else {
188 Context->ReportError(
189 PVD->getLocation(),
190 "Unexpected parameter '%0' for compute kernel %1()")
191 << PVD->getName() << FD->getName();
192 valid = false;
193 }
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700194 }
195 }
196
Chris Wailesc9454af2014-06-13 17:25:40 -0700197 if (mIns.empty() && !mOut) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800198 Context->ReportError(FD->getLocation(),
199 "Compute kernel %0() must have at least one "
200 "parameter for in or out")
201 << FD->getName();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700202 valid = false;
203 }
204
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700205 return valid;
206}
207
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800208bool RSExportForEach::validateAndConstructKernelParams(
209 RSContext *Context, const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700210 slangAssert(Context && FD);
211 bool valid = true;
212 clang::ASTContext &C = Context->getASTContext();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700213
214 if (Context->getTargetAPI() < SLANG_JB_MR1_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800215 Context->ReportError(FD->getLocation(),
216 "Compute kernel %0() targeting SDK levels "
217 "%1-%2 may not use pass-by-value with "
218 "__attribute__((kernel))")
219 << FD->getName() << SLANG_MINIMUM_TARGET_API
220 << (SLANG_JB_MR1_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700221 return false;
222 }
223
224 // Denote that we are indeed a pass-by-value kernel.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800225 mIsKernelStyle = true;
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800226 mHasReturnType = (mResultType != C.VoidTy);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700227
228 if (mResultType->isPointerType()) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800229 Context->ReportError(
230 FD->getTypeSpecStartLoc(),
231 "Compute kernel %0() cannot return a pointer type: '%1'")
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800232 << FD->getName() << mResultType.getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700233 valid = false;
234 }
235
236 // Validate remaining parameter types
Stephen Hines9ca96e72012-09-13 16:57:06 -0700237
David Gross18c50eb2015-01-30 11:39:22 -0800238 size_t IndexOfFirstSpecialParameter = numParams;
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700239 valid |= processSpecialParameters(Context, FD, &IndexOfFirstSpecialParameter);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700240
David Gross18c50eb2015-01-30 11:39:22 -0800241 // Validate the non-special parameters, which should all be found before the
242 // first special.
243 for (size_t i = 0; i < IndexOfFirstSpecialParameter; i++) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800244 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
Chris Wailesc9454af2014-06-13 17:25:40 -0700245
Stephen Hinesb3e022a2015-05-21 09:44:14 -0700246 if (Context->getTargetAPI() >= SLANG_M_TARGET_API || i == 0) {
David Grosscd7d3122015-03-13 15:11:44 -0700247 if (i >= RS_KERNEL_INPUT_LIMIT) {
248 Context->ReportError(PVD->getLocation(),
249 "Invalid parameter '%0' for compute kernel %1(). "
Stephen Hinesb3e022a2015-05-21 09:44:14 -0700250 "Kernels targeting SDK levels %2+ may not use "
251 "more than %3 input parameters.") << PVD->getName() <<
252 FD->getName() << SLANG_M_TARGET_API <<
253 int(RS_KERNEL_INPUT_LIMIT);
David Grosscd7d3122015-03-13 15:11:44 -0700254
255 } else {
256 mIns.push_back(PVD);
257 }
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800258 } else {
259 Context->ReportError(PVD->getLocation(),
Chris Wailesc9454af2014-06-13 17:25:40 -0700260 "Invalid parameter '%0' for compute kernel %1(). "
261 "Kernels targeting SDK levels %2-%3 may not use "
262 "multiple input parameters.") << PVD->getName() <<
263 FD->getName() << SLANG_MINIMUM_TARGET_API <<
Stephen Hinesb3e022a2015-05-21 09:44:14 -0700264 (SLANG_M_TARGET_API - 1);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800265 valid = false;
266 }
267 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700268 if (QT->isPointerType()) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800269 Context->ReportError(PVD->getLocation(),
270 "Compute kernel %0() cannot have "
271 "parameter '%1' of pointer type: '%2'")
272 << FD->getName() << PVD->getName() << PVD->getType().getAsString();
Stephen Hines9ca96e72012-09-13 16:57:06 -0700273 valid = false;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700274 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700275 }
276
277 // Check that we have at least one allocation to use for dimensions.
Stephen Hinesb3e022a2015-05-21 09:44:14 -0700278 if (valid && mIns.empty() && !mHasReturnType && Context->getTargetAPI() < SLANG_M_TARGET_API) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800279 Context->ReportError(FD->getLocation(),
David Grossfb78d4c2015-03-31 13:56:05 -0700280 "Compute kernel %0() targeting SDK levels "
281 "%1-%2 must have at least one "
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800282 "input parameter or a non-void return "
283 "type")
David Grossfb78d4c2015-03-31 13:56:05 -0700284 << FD->getName() << SLANG_MINIMUM_TARGET_API
Stephen Hinesb3e022a2015-05-21 09:44:14 -0700285 << (SLANG_M_TARGET_API - 1);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700286 valid = false;
287 }
288
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800289 return valid;
290}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700291
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700292// Process the optional special parameters:
293// - Sets *IndexOfFirstSpecialParameter to the index of the first special parameter, or
294// FD->getNumParams() if none are found.
295// - Sets mSpecialParameterSignatureMetadata for the found special parameters.
296// Returns true if no errors.
297bool RSExportForEach::processSpecialParameters(
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800298 RSContext *Context, const clang::FunctionDecl *FD,
David Gross18c50eb2015-01-30 11:39:22 -0800299 size_t *IndexOfFirstSpecialParameter) {
300 slangAssert(IndexOfFirstSpecialParameter != nullptr);
301 slangAssert(mSpecialParameterSignatureMetadata == 0);
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800302 clang::ASTContext &C = Context->getASTContext();
303
David Gross18c50eb2015-01-30 11:39:22 -0800304 // Find all special parameters if present.
305 int LastSpecialParameterIdx = -1; // index into specialParameterTable
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700306 int FirstLocationSpecialParameterIdx = -1; // index into specialParameterTable
307 clang::QualType FirstLocationSpecialParameterType;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800308 size_t NumParams = FD->getNumParams();
David Gross18c50eb2015-01-30 11:39:22 -0800309 *IndexOfFirstSpecialParameter = NumParams;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800310 bool valid = true;
311 for (size_t i = 0; i < NumParams; i++) {
312 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700313 const llvm::StringRef ParamName = PVD->getName();
314 const clang::QualType Type = PVD->getType();
315 const clang::QualType QT = Type.getCanonicalType();
316 const clang::QualType UT = QT.getUnqualifiedType();
David Gross18c50eb2015-01-30 11:39:22 -0800317 int SpecialParameterIdx = lookupSpecialParameter(ParamName);
David Gross18c50eb2015-01-30 11:39:22 -0800318
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700319 static const char KernelContextUnqualifiedTypeName[] =
320 "const struct rs_kernel_context_t *";
321 static const char KernelContextTypeName[] = "rs_kernel_context";
David Gross18c50eb2015-01-30 11:39:22 -0800322
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700323 // If the type is rs_context, it should have been named "context" and classified
324 // as a special parameter.
325 if (SpecialParameterIdx < 0 && UT.getAsString() == KernelContextUnqualifiedTypeName) {
326 Context->ReportError(
327 PVD->getLocation(),
328 "The special parameter of type '%0' must be called "
329 "'context' instead of '%1'.")
330 << KernelContextTypeName << ParamName;
331 SpecialParameterIdx = lookupSpecialParameter("context");
332 }
David Gross18c50eb2015-01-30 11:39:22 -0800333
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700334 // If it's not a special parameter, check that it appears before any special
335 // parameter.
336 if (SpecialParameterIdx < 0) {
David Gross18c50eb2015-01-30 11:39:22 -0800337 if (*IndexOfFirstSpecialParameter < NumParams) {
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800338 Context->ReportError(PVD->getLocation(),
339 "In compute kernel %0(), parameter '%1' cannot "
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700340 "appear after any of the special parameters (%2).")
David Gross18c50eb2015-01-30 11:39:22 -0800341 << FD->getName() << ParamName << listSpecialParameters(Context->getTargetAPI());
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800342 valid = false;
343 }
344 continue;
Stephen Hines9ca96e72012-09-13 16:57:06 -0700345 }
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700346
347 const SpecialParameter &SP = specialParameterTable[SpecialParameterIdx];
348
349 // Verify that this special parameter is OK for the current API level.
350 if (Context->getTargetAPI() < SP.minAPI) {
351 Context->ReportError(PVD->getLocation(),
352 "Compute kernel %0() targeting SDK levels "
353 "%1-%2 may not use special parameter '%3'.")
354 << FD->getName() << SLANG_MINIMUM_TARGET_API << (SP.minAPI - 1)
355 << SP.name;
356 valid = false;
Jean-Luc Brouillet42f81b22014-01-16 21:50:52 -0800357 }
Jean-Luc Brouillet9764eb32015-08-07 16:43:18 -0700358
359 // Check that the order of the special parameters is correct.
360 if (SpecialParameterIdx < LastSpecialParameterIdx) {
361 Context->ReportError(
362 PVD->getLocation(),
363 "In compute kernel %0(), special parameter '%1' must "
364 "be defined before special parameter '%2'.")
365 << FD->getName() << SP.name
366 << specialParameterTable[LastSpecialParameterIdx].name;
367 valid = false;
368 }
369
370 // Validate the data type of the special parameter.
371 switch (SP.kind) {
372 case SPK_LOCATION: {
373 // Location special parameters can only be int or uint.
374 if (UT != C.UnsignedIntTy && UT != C.IntTy) {
375 Context->ReportError(PVD->getLocation(),
376 "Special parameter '%0' must be of type 'int' or "
377 "'unsigned int'. It is of type '%1'.")
378 << ParamName << Type.getAsString();
379 valid = false;
380 }
381
382 // Ensure that all location special parameters have the same type.
383 if (FirstLocationSpecialParameterIdx >= 0) {
384 if (Type != FirstLocationSpecialParameterType) {
385 Context->ReportError(
386 PVD->getLocation(),
387 "Special parameters '%0' and '%1' must be of the same type. "
388 "'%0' is of type '%2' while '%1' is of type '%3'.")
389 << specialParameterTable[FirstLocationSpecialParameterIdx].name
390 << SP.name << FirstLocationSpecialParameterType.getAsString()
391 << Type.getAsString();
392 valid = false;
393 }
394 } else {
395 FirstLocationSpecialParameterIdx = SpecialParameterIdx;
396 FirstLocationSpecialParameterType = Type;
397 }
398 } break;
399 case SPK_CONTEXT: {
400 // Check that variables named "context" are of type rs_context.
401 if (UT.getAsString() != KernelContextUnqualifiedTypeName) {
402 Context->ReportError(PVD->getLocation(),
403 "Special parameter '%0' must be of type '%1'. "
404 "It is of type '%2'.")
405 << ParamName << KernelContextTypeName
406 << Type.getAsString();
407 valid = false;
408 }
409 } break;
410 default:
411 slangAssert(!"Unexpected special parameter type");
412 }
413
414 // We should not be invoked if two parameters of the same name are present.
415 slangAssert(!(mSpecialParameterSignatureMetadata & SP.bitval));
416 mSpecialParameterSignatureMetadata |= SP.bitval;
417
418 LastSpecialParameterIdx = SpecialParameterIdx;
David Gross18c50eb2015-01-30 11:39:22 -0800419 // If this is the first time we find a special parameter, save it.
420 if (*IndexOfFirstSpecialParameter >= NumParams) {
421 *IndexOfFirstSpecialParameter = i;
Jean-Luc Brouillet482caac2014-01-18 00:13:26 +0000422 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700423 }
Stephen Hines9ca96e72012-09-13 16:57:06 -0700424 return valid;
425}
426
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800427bool RSExportForEach::setSignatureMetadata(RSContext *Context,
428 const clang::FunctionDecl *FD) {
429 mSignatureMetadata = 0;
430 bool valid = true;
431
432 if (mIsKernelStyle) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700433 slangAssert(mOut == nullptr);
434 slangAssert(mUsrData == nullptr);
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800435 } else {
436 slangAssert(!mHasReturnType);
437 }
438
439 // Set up the bitwise metadata encoding for runtime argument passing.
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800440 const bool HasOut = mOut || mHasReturnType;
David Gross18c50eb2015-01-30 11:39:22 -0800441 mSignatureMetadata |= (hasIns() ? bcinfo::MD_SIG_In : 0);
442 mSignatureMetadata |= (HasOut ? bcinfo::MD_SIG_Out : 0);
443 mSignatureMetadata |= (mUsrData ? bcinfo::MD_SIG_Usr : 0);
444 mSignatureMetadata |= (mIsKernelStyle ? bcinfo::MD_SIG_Kernel : 0); // pass-by-value
445 mSignatureMetadata |= mSpecialParameterSignatureMetadata;
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800446
447 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
448 // APIs before ICS cannot skip between parameters. It is ok, however, for
449 // them to omit further parameters (i.e. skipping X is ok if you skip Y).
David Gross18c50eb2015-01-30 11:39:22 -0800450 if (mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
451 bcinfo::MD_SIG_X | bcinfo::MD_SIG_Y) &&
452 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr |
453 bcinfo::MD_SIG_X) &&
454 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out | bcinfo::MD_SIG_Usr) &&
455 mSignatureMetadata != (bcinfo::MD_SIG_In | bcinfo::MD_SIG_Out) &&
456 mSignatureMetadata != (bcinfo::MD_SIG_In)) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800457 Context->ReportError(FD->getLocation(),
458 "Compute kernel %0() targeting SDK levels "
459 "%1-%2 may not skip parameters")
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800460 << FD->getName() << SLANG_MINIMUM_TARGET_API
461 << (SLANG_ICS_TARGET_API - 1);
462 valid = false;
463 }
464 }
465 return valid;
466}
Stephen Hines9ca96e72012-09-13 16:57:06 -0700467
Stephen Hines593a8942011-05-10 15:29:50 -0700468RSExportForEach *RSExportForEach::Create(RSContext *Context,
469 const clang::FunctionDecl *FD) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700470 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700471 llvm::StringRef Name = FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700472 RSExportForEach *FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700473
474 slangAssert(!Name.empty() && "Function must have a name");
475
Stephen Hinesc17e1982012-02-22 12:30:45 -0800476 FE = new RSExportForEach(Context, Name);
Stephen Hines593a8942011-05-10 15:29:50 -0700477
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700478 if (!FE->validateAndConstructParams(Context, FD)) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700479 return nullptr;
Stephen Hines593a8942011-05-10 15:29:50 -0700480 }
481
482 clang::ASTContext &Ctx = Context->getASTContext();
483
Jean-Luc Brouilleteca05342014-05-15 12:44:21 -0700484 std::string Id = CreateDummyName("helper_foreach_param", FE->getName());
Stephen Hines593a8942011-05-10 15:29:50 -0700485
486 // Extract the usrData parameter (if we have one)
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700487 if (FE->mUsrData) {
488 const clang::ParmVarDecl *PVD = FE->mUsrData;
Stephen Hines593a8942011-05-10 15:29:50 -0700489 clang::QualType QT = PVD->getType().getCanonicalType();
490 slangAssert(QT->isPointerType() &&
491 QT->getPointeeType().isConstQualified());
492
493 const clang::ASTContext &C = Context->getASTContext();
494 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
495 C.VoidTy) {
496 // In the case of using const void*, we can't reflect an appopriate
497 // Java type, so we fall back to just reflecting the ain/aout parameters
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700498 FE->mUsrData = nullptr;
Stephen Hines593a8942011-05-10 15:29:50 -0700499 } else {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700500 clang::RecordDecl *RD =
501 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
502 Ctx.getTranslationUnitDecl(),
503 clang::SourceLocation(),
504 clang::SourceLocation(),
505 &Ctx.Idents.get(Id));
506
Stephen Hines593a8942011-05-10 15:29:50 -0700507 clang::FieldDecl *FD =
508 clang::FieldDecl::Create(Ctx,
509 RD,
510 clang::SourceLocation(),
511 clang::SourceLocation(),
512 PVD->getIdentifier(),
513 QT->getPointeeType(),
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700514 nullptr,
515 /* BitWidth = */ nullptr,
Shih-wei Liao1688a3c2011-06-22 05:21:27 -0700516 /* Mutable = */ false,
Shih-wei Liao43730fe2012-08-02 23:06:18 -0700517 /* HasInit = */ clang::ICIS_NoInit);
Stephen Hines593a8942011-05-10 15:29:50 -0700518 RD->addDecl(FD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700519 RD->completeDefinition();
520
521 // Create an export type iff we have a valid usrData type
522 clang::QualType T = Ctx.getTagDeclType(RD);
523 slangAssert(!T.isNull());
524
525 RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
526
Stephen Hinese23d82b2015-06-11 17:00:04 -0700527 slangAssert(ET && "Failed to export a kernel");
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700528
529 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
530 "Parameter packet must be a record");
531
532 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
Stephen Hines593a8942011-05-10 15:29:50 -0700533 }
534 }
Stephen Hines593a8942011-05-10 15:29:50 -0700535
Chris Wailesc9454af2014-06-13 17:25:40 -0700536 if (FE->hasIns()) {
537
538 for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
539 const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
540 RSExportType *InExportType = RSExportType::Create(Context, T);
541
542 if (FE->mIsKernelStyle) {
Chris Wailes5abbe0e2014-08-12 15:58:29 -0700543 slangAssert(InExportType != nullptr);
Chris Wailesc9454af2014-06-13 17:25:40 -0700544 }
545
546 FE->mInTypes.push_back(InExportType);
Stephen Hines9ca96e72012-09-13 16:57:06 -0700547 }
Stephen Hines593a8942011-05-10 15:29:50 -0700548 }
Stephen Hines5baf6322011-04-25 17:21:15 -0700549
Jean-Luc Brouillet0f2a2392014-01-14 11:40:57 -0800550 if (FE->mIsKernelStyle && FE->mHasReturnType) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700551 const clang::Type *T = FE->mResultType.getTypePtr();
552 FE->mOutType = RSExportType::Create(Context, T);
553 slangAssert(FE->mOutType);
554 } else if (FE->mOut) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700555 const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
556 FE->mOutType = RSExportType::Create(Context, T);
557 }
558
559 return FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700560}
561
Stephen Hinesc17e1982012-02-22 12:30:45 -0800562RSExportForEach *RSExportForEach::CreateDummyRoot(RSContext *Context) {
563 slangAssert(Context);
564 llvm::StringRef Name = "root";
565 RSExportForEach *FE = new RSExportForEach(Context, Name);
566 FE->mDummyRoot = true;
567 return FE;
568}
569
Chris Wailesc9454af2014-06-13 17:25:40 -0700570bool RSExportForEach::isGraphicsRootRSFunc(unsigned int targetAPI,
Stephen Hines9999ec32012-02-10 18:22:14 -0800571 const clang::FunctionDecl *FD) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700572 if (FD->hasAttr<clang::KernelAttr>()) {
573 return false;
574 }
575
Stephen Hines9999ec32012-02-10 18:22:14 -0800576 if (!isRootRSFunc(FD)) {
577 return false;
578 }
579
580 if (FD->getNumParams() == 0) {
581 // Graphics root function
582 return true;
583 }
584
585 // Check for legacy graphics root function (with single parameter).
586 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
587 const clang::QualType &IntType = FD->getASTContext().IntTy;
Tim Murrayee4016d2014-04-10 15:49:08 -0700588 if (FD->getReturnType().getCanonicalType() == IntType) {
Stephen Hines9999ec32012-02-10 18:22:14 -0800589 return true;
590 }
591 }
592
593 return false;
594}
595
Chris Wailesc9454af2014-06-13 17:25:40 -0700596bool RSExportForEach::isRSForEachFunc(unsigned int targetAPI,
597 slang::RSContext* Context,
598 const clang::FunctionDecl *FD) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800599 slangAssert(Context && FD);
Stephen Hines089cde32012-12-07 19:19:10 -0800600 bool hasKernelAttr = FD->hasAttr<clang::KernelAttr>();
601
602 if (FD->getStorageClass() == clang::SC_Static) {
603 if (hasKernelAttr) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800604 Context->ReportError(FD->getLocation(),
605 "Invalid use of attribute kernel with "
606 "static function declaration: %0")
607 << FD->getName();
Stephen Hines089cde32012-12-07 19:19:10 -0800608 }
609 return false;
610 }
611
Stephen Hines9ca96e72012-09-13 16:57:06 -0700612 // Anything tagged as a kernel is definitely used with ForEach.
Stephen Hines089cde32012-12-07 19:19:10 -0800613 if (hasKernelAttr) {
Stephen Hines9ca96e72012-09-13 16:57:06 -0700614 return true;
615 }
616
Stephen Hines9999ec32012-02-10 18:22:14 -0800617 if (isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700618 return false;
619 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700620
Stephen Hines7b51b552012-02-16 00:12:38 -0800621 // Check if first parameter is a pointer (which is required for ForEach).
622 unsigned int numParams = FD->getNumParams();
623
624 if (numParams > 0) {
625 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
626 clang::QualType QT = PVD->getType().getCanonicalType();
627
628 if (QT->isPointerType()) {
629 return true;
630 }
631
632 // Any non-graphics root() is automatically a ForEach candidate.
633 // At this point, however, we know that it is not going to be a valid
634 // compute root() function (due to not having a pointer parameter). We
635 // still want to return true here, so that we can issue appropriate
636 // diagnostics.
637 if (isRootRSFunc(FD)) {
638 return true;
639 }
640 }
641
642 return false;
Stephen Hines593a8942011-05-10 15:29:50 -0700643}
644
Logan Chien9207a2e2011-10-21 15:39:28 +0800645bool
Chris Wailesc9454af2014-06-13 17:25:40 -0700646RSExportForEach::validateSpecialFuncDecl(unsigned int targetAPI,
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800647 slang::RSContext *Context,
Logan Chien9207a2e2011-10-21 15:39:28 +0800648 clang::FunctionDecl const *FD) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800649 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700650 bool valid = true;
651 const clang::ASTContext &C = FD->getASTContext();
Stephen Hines9999ec32012-02-10 18:22:14 -0800652 const clang::QualType &IntType = FD->getASTContext().IntTy;
Stephen Hines5baf6322011-04-25 17:21:15 -0700653
Stephen Hines9999ec32012-02-10 18:22:14 -0800654 if (isGraphicsRootRSFunc(targetAPI, FD)) {
655 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
656 // Legacy graphics root function
657 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
658 clang::QualType QT = PVD->getType().getCanonicalType();
659 if (QT != IntType) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800660 Context->ReportError(PVD->getLocation(),
661 "invalid parameter type for legacy "
662 "graphics root() function: %0")
663 << PVD->getType();
Stephen Hines5baf6322011-04-25 17:21:15 -0700664 valid = false;
665 }
Stephen Hines9999ec32012-02-10 18:22:14 -0800666 }
667
668 // Graphics root function, so verify that it returns an int
Tim Murrayee4016d2014-04-10 15:49:08 -0700669 if (FD->getReturnType().getCanonicalType() != IntType) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800670 Context->ReportError(FD->getLocation(),
671 "root() is required to return "
672 "an int for graphics usage");
Stephen Hines9999ec32012-02-10 18:22:14 -0800673 valid = false;
Stephen Hines5baf6322011-04-25 17:21:15 -0700674 }
Stephen Hines688e64b2011-08-23 16:01:25 -0700675 } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
Stephen Hines5baf6322011-04-25 17:21:15 -0700676 if (FD->getNumParams() != 0) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800677 Context->ReportError(FD->getLocation(),
678 "%0(void) is required to have no "
679 "parameters")
680 << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700681 valid = false;
682 }
683
Tim Murrayee4016d2014-04-10 15:49:08 -0700684 if (FD->getReturnType().getCanonicalType() != C.VoidTy) {
Jean-Luc Brouilletd3f75272014-01-16 18:20:28 -0800685 Context->ReportError(FD->getLocation(),
686 "%0(void) is required to have a void "
687 "return type")
688 << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700689 valid = false;
690 }
Stephen Hines3cb586a2011-05-05 18:20:22 -0700691 } else {
Stephen Hines688e64b2011-08-23 16:01:25 -0700692 slangAssert(false && "must be called on root, init or .rs.dtor function!");
Stephen Hines5baf6322011-04-25 17:21:15 -0700693 }
694
695 return valid;
696}
697
698} // namespace slang