blob: 76eb0f168968706636f22efc37e86ba7fa1dd1b8 [file] [log] [blame]
Stephen Hines5baf6322011-04-25 17:21:15 -07001/*
Stephen Hines9999ec32012-02-10 18:22:14 -08002 * Copyright 2011-2012, The Android Open Source Project
Stephen Hines5baf6322011-04-25 17:21:15 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Stephen Hines593a8942011-05-10 15:29:50 -070017#include "slang_rs_export_foreach.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070018
19#include <string>
20
21#include "clang/AST/ASTContext.h"
22#include "clang/AST/Decl.h"
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070023#include "clang/AST/TypeLoc.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070024
25#include "llvm/DerivedTypes.h"
26#include "llvm/Target/TargetData.h"
27
28#include "slang_assert.h"
29#include "slang_rs_context.h"
Stephen Hines593a8942011-05-10 15:29:50 -070030#include "slang_rs_export_type.h"
Stephen Hines12580dc2011-10-10 17:44:10 -070031#include "slang_version.h"
Stephen Hines5baf6322011-04-25 17:21:15 -070032
33namespace slang {
34
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070035namespace {
36
Logan Chien9207a2e2011-10-21 15:39:28 +080037static void ReportNameError(clang::DiagnosticsEngine *DiagEngine,
38 clang::ParmVarDecl const *PVD) {
39 slangAssert(DiagEngine && PVD);
40 const clang::SourceManager &SM = DiagEngine->getSourceManager();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070041
Logan Chien9207a2e2011-10-21 15:39:28 +080042 DiagEngine->Report(
43 clang::FullSourceLoc(PVD->getLocation(), SM),
44 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
45 "Duplicate parameter entry "
46 "(by position/name): '%0'"))
47 << PVD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070048 return;
49}
50
51} // namespace
52
53// This function takes care of additional validation and construction of
54// parameters related to forEach_* reflection.
55bool RSExportForEach::validateAndConstructParams(
56 RSContext *Context, const clang::FunctionDecl *FD) {
57 slangAssert(Context && FD);
58 bool valid = true;
59 clang::ASTContext &C = Context->getASTContext();
Logan Chien9207a2e2011-10-21 15:39:28 +080060 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070061
62 if (!isRootRSFunc(FD)) {
63 slangAssert(false && "must be called on compute root function!");
64 }
65
66 numParams = FD->getNumParams();
67 slangAssert(numParams > 0);
68
69 // Compute root functions are required to return a void type for now
70 if (FD->getResultType().getCanonicalType() != C.VoidTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +080071 DiagEngine->Report(
72 clang::FullSourceLoc(FD->getLocation(), DiagEngine->getSourceManager()),
73 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
74 "compute root() is required to return a "
75 "void type"));
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070076 valid = false;
77 }
78
79 // Validate remaining parameter types
80 // TODO(all): Add support for LOD/face when we have them
81
Stephen Hines4ccf75e2011-08-16 18:21:01 -070082 size_t i = 0;
83 const clang::ParmVarDecl *PVD = FD->getParamDecl(i);
84 clang::QualType QT = PVD->getType().getCanonicalType();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -070085
Stephen Hines4ccf75e2011-08-16 18:21:01 -070086 // Check for const T1 *in
87 if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) {
88 mIn = PVD;
89 i++; // advance parameter pointer
90 }
91
92 // Check for T2 *out
93 if (i < numParams) {
94 PVD = FD->getParamDecl(i);
95 QT = PVD->getType().getCanonicalType();
96 if (QT->isPointerType() && !QT->getPointeeType().isConstQualified()) {
97 mOut = PVD;
98 i++; // advance parameter pointer
99 }
100 }
101
102 if (!mIn && !mOut) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800103 DiagEngine->Report(
104 clang::FullSourceLoc(FD->getLocation(),
105 DiagEngine->getSourceManager()),
106 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
107 "Compute root() must have at least one "
108 "parameter for in or out"));
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700109 valid = false;
110 }
111
112 // Check for T3 *usrData
113 if (i < numParams) {
114 PVD = FD->getParamDecl(i);
115 QT = PVD->getType().getCanonicalType();
116 if (QT->isPointerType() && QT->getPointeeType().isConstQualified()) {
117 mUsrData = PVD;
118 i++; // advance parameter pointer
119 }
120 }
121
122 while (i < numParams) {
123 PVD = FD->getParamDecl(i);
124 QT = PVD->getType().getCanonicalType();
125
126 if (QT.getUnqualifiedType() != C.UnsignedIntTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800127 DiagEngine->Report(
128 clang::FullSourceLoc(PVD->getLocation(),
129 DiagEngine->getSourceManager()),
130 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
131 "Unexpected root() parameter '%0' "
132 "of type '%1'"))
133 << PVD->getName() << PVD->getType().getAsString();
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700134 valid = false;
135 } else {
136 llvm::StringRef ParamName = PVD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700137 if (ParamName.equals("x")) {
138 if (mX) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800139 ReportNameError(DiagEngine, PVD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700140 valid = false;
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700141 } else if (mY) {
142 // Can't go back to X after skipping Y
Logan Chien9207a2e2011-10-21 15:39:28 +0800143 ReportNameError(DiagEngine, PVD);
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700144 valid = false;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700145 } else {
146 mX = PVD;
147 }
148 } else if (ParamName.equals("y")) {
149 if (mY) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800150 ReportNameError(DiagEngine, PVD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700151 valid = false;
152 } else {
153 mY = PVD;
154 }
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700155 } else {
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700156 if (!mX && !mY) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700157 mX = PVD;
158 } else if (!mY) {
159 mY = PVD;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700160 } else {
Logan Chien9207a2e2011-10-21 15:39:28 +0800161 DiagEngine->Report(
162 clang::FullSourceLoc(PVD->getLocation(),
163 DiagEngine->getSourceManager()),
164 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
165 "Unexpected root() parameter '%0' "
166 "of type '%1'"))
167 << PVD->getName() << PVD->getType().getAsString();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700168 valid = false;
169 }
170 }
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700171 }
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700172
173 i++;
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700174 }
175
Stephen Hines4ccf75e2011-08-16 18:21:01 -0700176 mMetadataEncoding = 0;
177 if (valid) {
178 // Set up the bitwise metadata encoding for runtime argument passing.
179 mMetadataEncoding |= (mIn ? 0x01 : 0);
180 mMetadataEncoding |= (mOut ? 0x02 : 0);
181 mMetadataEncoding |= (mUsrData ? 0x04 : 0);
182 mMetadataEncoding |= (mX ? 0x08 : 0);
183 mMetadataEncoding |= (mY ? 0x10 : 0);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700184 }
185
Stephen Hines12580dc2011-10-10 17:44:10 -0700186 if (Context->getTargetAPI() < SLANG_ICS_TARGET_API) {
187 // APIs before ICS cannot skip between parameters. It is ok, however, for
188 // them to omit further parameters (i.e. skipping X is ok if you skip Y).
189 if (mMetadataEncoding != 0x1f && // In, Out, UsrData, X, Y
190 mMetadataEncoding != 0x0f && // In, Out, UsrData, X
191 mMetadataEncoding != 0x07 && // In, Out, UsrData
192 mMetadataEncoding != 0x03 && // In, Out
193 mMetadataEncoding != 0x01) { // In
Logan Chien9207a2e2011-10-21 15:39:28 +0800194 DiagEngine->Report(
195 clang::FullSourceLoc(FD->getLocation(),
196 DiagEngine->getSourceManager()),
197 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
198 "Compute root() targeting SDK levels "
199 "%0-%1 may not skip parameters"))
200 << SLANG_MINIMUM_TARGET_API << (SLANG_ICS_TARGET_API-1);
Stephen Hines12580dc2011-10-10 17:44:10 -0700201 valid = false;
202 }
203 }
204
205
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700206 return valid;
207}
208
Stephen Hines593a8942011-05-10 15:29:50 -0700209RSExportForEach *RSExportForEach::Create(RSContext *Context,
210 const clang::FunctionDecl *FD) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700211 slangAssert(Context && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700212 llvm::StringRef Name = FD->getName();
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700213 RSExportForEach *FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700214
215 slangAssert(!Name.empty() && "Function must have a name");
216
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700217 FE = new RSExportForEach(Context, Name, FD);
Stephen Hines593a8942011-05-10 15:29:50 -0700218
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700219 if (!FE->validateAndConstructParams(Context, FD)) {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700220 return NULL;
Stephen Hines593a8942011-05-10 15:29:50 -0700221 }
222
223 clang::ASTContext &Ctx = Context->getASTContext();
224
225 std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:");
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700226 Id.append(FE->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX);
Stephen Hines593a8942011-05-10 15:29:50 -0700227
228 // Extract the usrData parameter (if we have one)
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700229 if (FE->mUsrData) {
230 const clang::ParmVarDecl *PVD = FE->mUsrData;
Stephen Hines593a8942011-05-10 15:29:50 -0700231 clang::QualType QT = PVD->getType().getCanonicalType();
232 slangAssert(QT->isPointerType() &&
233 QT->getPointeeType().isConstQualified());
234
235 const clang::ASTContext &C = Context->getASTContext();
236 if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() ==
237 C.VoidTy) {
238 // In the case of using const void*, we can't reflect an appopriate
239 // Java type, so we fall back to just reflecting the ain/aout parameters
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700240 FE->mUsrData = NULL;
Stephen Hines593a8942011-05-10 15:29:50 -0700241 } else {
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700242 clang::RecordDecl *RD =
243 clang::RecordDecl::Create(Ctx, clang::TTK_Struct,
244 Ctx.getTranslationUnitDecl(),
245 clang::SourceLocation(),
246 clang::SourceLocation(),
247 &Ctx.Idents.get(Id));
248
Stephen Hines593a8942011-05-10 15:29:50 -0700249 clang::FieldDecl *FD =
250 clang::FieldDecl::Create(Ctx,
251 RD,
252 clang::SourceLocation(),
253 clang::SourceLocation(),
254 PVD->getIdentifier(),
255 QT->getPointeeType(),
256 NULL,
Shih-wei Liao1688a3c2011-06-22 05:21:27 -0700257 /* BitWidth = */ NULL,
258 /* Mutable = */ false,
259 /* HasInit = */ false);
Stephen Hines593a8942011-05-10 15:29:50 -0700260 RD->addDecl(FD);
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700261 RD->completeDefinition();
262
263 // Create an export type iff we have a valid usrData type
264 clang::QualType T = Ctx.getTagDeclType(RD);
265 slangAssert(!T.isNull());
266
267 RSExportType *ET = RSExportType::Create(Context, T.getTypePtr());
268
269 if (ET == NULL) {
270 fprintf(stderr, "Failed to export the function %s. There's at least "
271 "one parameter whose type is not supported by the "
272 "reflection\n", FE->getName().c_str());
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700273 return NULL;
274 }
275
276 slangAssert((ET->getClass() == RSExportType::ExportClassRecord) &&
277 "Parameter packet must be a record");
278
279 FE->mParamPacketType = static_cast<RSExportRecordType *>(ET);
Stephen Hines593a8942011-05-10 15:29:50 -0700280 }
281 }
Stephen Hines593a8942011-05-10 15:29:50 -0700282
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700283 if (FE->mIn) {
284 const clang::Type *T = FE->mIn->getType().getCanonicalType().getTypePtr();
285 FE->mInType = RSExportType::Create(Context, T);
Stephen Hines593a8942011-05-10 15:29:50 -0700286 }
Stephen Hines5baf6322011-04-25 17:21:15 -0700287
Stephen Hinesb5a89fb2011-05-17 14:48:02 -0700288 if (FE->mOut) {
289 const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
290 FE->mOutType = RSExportType::Create(Context, T);
291 }
292
293 return FE;
Stephen Hines5baf6322011-04-25 17:21:15 -0700294}
295
Stephen Hines9999ec32012-02-10 18:22:14 -0800296bool RSExportForEach::isGraphicsRootRSFunc(int targetAPI,
297 const clang::FunctionDecl *FD) {
298 if (!isRootRSFunc(FD)) {
299 return false;
300 }
301
302 if (FD->getNumParams() == 0) {
303 // Graphics root function
304 return true;
305 }
306
307 // Check for legacy graphics root function (with single parameter).
308 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
309 const clang::QualType &IntType = FD->getASTContext().IntTy;
310 if (FD->getResultType().getCanonicalType() == IntType) {
311 return true;
312 }
313 }
314
315 return false;
316}
317
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700318bool RSExportForEach::isRSForEachFunc(int targetAPI,
319 const clang::FunctionDecl *FD) {
Stephen Hines593a8942011-05-10 15:29:50 -0700320 // We currently support only compute root() being exported via forEach
321 if (!isRootRSFunc(FD)) {
322 return false;
323 }
324
Stephen Hines9999ec32012-02-10 18:22:14 -0800325 if (isGraphicsRootRSFunc(targetAPI, FD)) {
Stephen Hines593a8942011-05-10 15:29:50 -0700326 return false;
327 }
Stephen Hinesf736d5a2011-10-26 16:18:14 -0700328
Stephen Hines593a8942011-05-10 15:29:50 -0700329 return true;
330}
331
Logan Chien9207a2e2011-10-21 15:39:28 +0800332bool
Stephen Hinesfbfd7f52011-10-27 16:09:01 -0700333RSExportForEach::validateSpecialFuncDecl(int targetAPI,
334 clang::DiagnosticsEngine *DiagEngine,
Logan Chien9207a2e2011-10-21 15:39:28 +0800335 clang::FunctionDecl const *FD) {
336 slangAssert(DiagEngine && FD);
Stephen Hines5baf6322011-04-25 17:21:15 -0700337 bool valid = true;
338 const clang::ASTContext &C = FD->getASTContext();
Stephen Hines9999ec32012-02-10 18:22:14 -0800339 const clang::QualType &IntType = FD->getASTContext().IntTy;
Stephen Hines5baf6322011-04-25 17:21:15 -0700340
Stephen Hines9999ec32012-02-10 18:22:14 -0800341 if (isGraphicsRootRSFunc(targetAPI, FD)) {
342 if ((targetAPI < SLANG_ICS_TARGET_API) && (FD->getNumParams() == 1)) {
343 // Legacy graphics root function
344 const clang::ParmVarDecl *PVD = FD->getParamDecl(0);
345 clang::QualType QT = PVD->getType().getCanonicalType();
346 if (QT != IntType) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800347 DiagEngine->Report(
Stephen Hines9999ec32012-02-10 18:22:14 -0800348 clang::FullSourceLoc(PVD->getLocation(),
Logan Chien9207a2e2011-10-21 15:39:28 +0800349 DiagEngine->getSourceManager()),
350 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
Stephen Hines9999ec32012-02-10 18:22:14 -0800351 "invalid parameter type for legacy "
352 "graphics root() function: %0"))
353 << PVD->getType();
Stephen Hines5baf6322011-04-25 17:21:15 -0700354 valid = false;
355 }
Stephen Hines9999ec32012-02-10 18:22:14 -0800356 }
357
358 // Graphics root function, so verify that it returns an int
359 if (FD->getResultType().getCanonicalType() != IntType) {
360 DiagEngine->Report(
361 clang::FullSourceLoc(FD->getLocation(),
362 DiagEngine->getSourceManager()),
363 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
364 "root() is required to return "
365 "an int for graphics usage"));
366 valid = false;
Stephen Hines5baf6322011-04-25 17:21:15 -0700367 }
Stephen Hines688e64b2011-08-23 16:01:25 -0700368 } else if (isInitRSFunc(FD) || isDtorRSFunc(FD)) {
Stephen Hines5baf6322011-04-25 17:21:15 -0700369 if (FD->getNumParams() != 0) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800370 DiagEngine->Report(
371 clang::FullSourceLoc(FD->getLocation(),
372 DiagEngine->getSourceManager()),
373 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
374 "%0(void) is required to have no "
375 "parameters")) << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700376 valid = false;
377 }
378
379 if (FD->getResultType().getCanonicalType() != C.VoidTy) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800380 DiagEngine->Report(
381 clang::FullSourceLoc(FD->getLocation(),
382 DiagEngine->getSourceManager()),
383 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
384 "%0(void) is required to have a void "
385 "return type")) << FD->getName();
Stephen Hines5baf6322011-04-25 17:21:15 -0700386 valid = false;
387 }
Stephen Hines3cb586a2011-05-05 18:20:22 -0700388 } else {
Stephen Hines688e64b2011-08-23 16:01:25 -0700389 slangAssert(false && "must be called on root, init or .rs.dtor function!");
Stephen Hines5baf6322011-04-25 17:21:15 -0700390 }
391
392 return valid;
393}
394
395} // namespace slang