1 /*
2 * Copyright 2010-2012, The Android Open Source Project
3 *
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
17 #include "slang_rs_export_type.h"
18
19 #include <list>
20 #include <vector>
21
22 #include "clang/AST/ASTContext.h"
23 #include "clang/AST/Attr.h"
24 #include "clang/AST/RecordLayout.h"
25
26 #include "llvm/ADT/StringExtras.h"
27 #include "llvm/IR/DataLayout.h"
28 #include "llvm/IR/DerivedTypes.h"
29 #include "llvm/IR/Type.h"
30
31 #include "slang_assert.h"
32 #include "slang_rs_context.h"
33 #include "slang_rs_export_element.h"
34 #include "slang_rs_type_spec.h"
35 #include "slang_version.h"
36
37 #define CHECK_PARENT_EQUALITY(ParentClass, E) \
38 if (!ParentClass::equals(E)) \
39 return false;
40
41 namespace slang {
42
43 namespace {
44
45 static RSReflectionType gReflectionTypes[] = {
46 {"FLOAT_16", "F16", 16, "half", "half", "Half", "Half", false},
47 {"FLOAT_32", "F32", 32, "float", "float", "Float", "Float", false},
48 {"FLOAT_64", "F64", 64, "double", "double", "Double", "Double",false},
49 {"SIGNED_8", "I8", 8, "int8_t", "byte", "Byte", "Byte", false},
50 {"SIGNED_16", "I16", 16, "int16_t", "short", "Short", "Short", false},
51 {"SIGNED_32", "I32", 32, "int32_t", "int", "Int", "Int", false},
52 {"SIGNED_64", "I64", 64, "int64_t", "long", "Long", "Long", false},
53 {"UNSIGNED_8", "U8", 8, "uint8_t", "short", "UByte", "Short", true},
54 {"UNSIGNED_16", "U16", 16, "uint16_t", "int", "UShort", "Int", true},
55 {"UNSIGNED_32", "U32", 32, "uint32_t", "long", "UInt", "Long", true},
56 {"UNSIGNED_64", "U64", 64, "uint64_t", "long", "ULong", "Long", false},
57
58 {"BOOLEAN", "BOOLEAN", 8, "bool", "boolean", NULL, NULL, false},
59
60 {"UNSIGNED_5_6_5", NULL, 16, NULL, NULL, NULL, NULL, false},
61 {"UNSIGNED_5_5_5_1", NULL, 16, NULL, NULL, NULL, NULL, false},
62 {"UNSIGNED_4_4_4_4", NULL, 16, NULL, NULL, NULL, NULL, false},
63
64 {"MATRIX_2X2", NULL, 4*32, "rsMatrix_2x2", "Matrix2f", NULL, NULL, false},
65 {"MATRIX_3X3", NULL, 9*32, "rsMatrix_3x3", "Matrix3f", NULL, NULL, false},
66 {"MATRIX_4X4", NULL, 16*32, "rsMatrix_4x4", "Matrix4f", NULL, NULL, false},
67
68 {"RS_ELEMENT", "ELEMENT", 32, "Element", "Element", NULL, NULL, false},
69 {"RS_TYPE", "TYPE", 32, "Type", "Type", NULL, NULL, false},
70 {"RS_ALLOCATION", "ALLOCATION", 32, "Allocation", "Allocation", NULL, NULL, false},
71 {"RS_SAMPLER", "SAMPLER", 32, "Sampler", "Sampler", NULL, NULL, false},
72 {"RS_SCRIPT", "SCRIPT", 32, "Script", "Script", NULL, NULL, false},
73 {"RS_MESH", "MESH", 32, "Mesh", "Mesh", NULL, NULL, false},
74 {"RS_PATH", "PATH", 32, "Path", "Path", NULL, NULL, false},
75 {"RS_PROGRAM_FRAGMENT", "PROGRAM_FRAGMENT", 32, "ProgramFragment", "ProgramFragment", NULL, NULL, false},
76 {"RS_PROGRAM_VERTEX", "PROGRAM_VERTEX", 32, "ProgramVertex", "ProgramVertex", NULL, NULL, false},
77 {"RS_PROGRAM_RASTER", "PROGRAM_RASTER", 32, "ProgramRaster", "ProgramRaster", NULL, NULL, false},
78 {"RS_PROGRAM_STORE", "PROGRAM_STORE", 32, "ProgramStore", "ProgramStore", NULL, NULL, false},
79 {"RS_FONT", "FONT", 32, "Font", "Font", NULL, NULL, false}
80 };
81
82 static const clang::Type *TypeExportableHelper(
83 const clang::Type *T,
84 llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
85 clang::DiagnosticsEngine *DiagEngine,
86 const clang::VarDecl *VD,
87 const clang::RecordDecl *TopLevelRecord);
88
ReportTypeError(clang::DiagnosticsEngine * DiagEngine,const clang::NamedDecl * ND,const clang::RecordDecl * TopLevelRecord,const char * Message,unsigned int TargetAPI=0)89 static void ReportTypeError(clang::DiagnosticsEngine *DiagEngine,
90 const clang::NamedDecl *ND,
91 const clang::RecordDecl *TopLevelRecord,
92 const char *Message,
93 unsigned int TargetAPI = 0) {
94 if (!DiagEngine) {
95 return;
96 }
97
98 const clang::SourceManager &SM = DiagEngine->getSourceManager();
99
100 // Attempt to use the type declaration first (if we have one).
101 // Fall back to the variable definition, if we are looking at something
102 // like an array declaration that can't be exported.
103 if (TopLevelRecord) {
104 DiagEngine->Report(
105 clang::FullSourceLoc(TopLevelRecord->getLocation(), SM),
106 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, Message))
107 << TopLevelRecord->getName() << TargetAPI;
108 } else if (ND) {
109 DiagEngine->Report(
110 clang::FullSourceLoc(ND->getLocation(), SM),
111 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, Message))
112 << ND->getName() << TargetAPI;
113 } else {
114 slangAssert(false && "Variables should be validated before exporting");
115 }
116 }
117
ConstantArrayTypeExportableHelper(const clang::ConstantArrayType * CAT,llvm::SmallPtrSet<const clang::Type *,8> & SPS,clang::DiagnosticsEngine * DiagEngine,const clang::VarDecl * VD,const clang::RecordDecl * TopLevelRecord)118 static const clang::Type *ConstantArrayTypeExportableHelper(
119 const clang::ConstantArrayType *CAT,
120 llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
121 clang::DiagnosticsEngine *DiagEngine,
122 const clang::VarDecl *VD,
123 const clang::RecordDecl *TopLevelRecord) {
124 // Check element type
125 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
126 if (ElementType->isArrayType()) {
127 ReportTypeError(DiagEngine, VD, TopLevelRecord,
128 "multidimensional arrays cannot be exported: '%0'");
129 return NULL;
130 } else if (ElementType->isExtVectorType()) {
131 const clang::ExtVectorType *EVT =
132 static_cast<const clang::ExtVectorType*>(ElementType);
133 unsigned numElements = EVT->getNumElements();
134
135 const clang::Type *BaseElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
136 if (!RSExportPrimitiveType::IsPrimitiveType(BaseElementType)) {
137 ReportTypeError(DiagEngine, VD, TopLevelRecord,
138 "vectors of non-primitive types cannot be exported: '%0'");
139 return NULL;
140 }
141
142 if (numElements == 3 && CAT->getSize() != 1) {
143 ReportTypeError(DiagEngine, VD, TopLevelRecord,
144 "arrays of width 3 vector types cannot be exported: '%0'");
145 return NULL;
146 }
147 }
148
149 if (TypeExportableHelper(ElementType, SPS, DiagEngine, VD,
150 TopLevelRecord) == NULL) {
151 return NULL;
152 } else {
153 return CAT;
154 }
155 }
156
TypeExportableHelper(clang::Type const * T,llvm::SmallPtrSet<clang::Type const *,8> & SPS,clang::DiagnosticsEngine * DiagEngine,clang::VarDecl const * VD,clang::RecordDecl const * TopLevelRecord)157 static const clang::Type *TypeExportableHelper(
158 clang::Type const *T,
159 llvm::SmallPtrSet<clang::Type const *, 8> &SPS,
160 clang::DiagnosticsEngine *DiagEngine,
161 clang::VarDecl const *VD,
162 clang::RecordDecl const *TopLevelRecord) {
163 // Normalize first
164 if ((T = GET_CANONICAL_TYPE(T)) == NULL)
165 return NULL;
166
167 if (SPS.count(T))
168 return T;
169
170 switch (T->getTypeClass()) {
171 case clang::Type::Builtin: {
172 const clang::BuiltinType *BT =
173 UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
174
175 switch (BT->getKind()) {
176 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname) \
177 case builtin_type:
178 #include "RSClangBuiltinEnums.inc"
179 return T;
180 default: {
181 return NULL;
182 }
183 }
184 }
185 case clang::Type::Record: {
186 if (RSExportPrimitiveType::GetRSSpecificType(T) !=
187 RSExportPrimitiveType::DataTypeUnknown) {
188 return T; // RS object type, no further checks are needed
189 }
190
191 // Check internal struct
192 if (T->isUnionType()) {
193 ReportTypeError(DiagEngine, VD, T->getAsUnionType()->getDecl(),
194 "unions cannot be exported: '%0'");
195 return NULL;
196 } else if (!T->isStructureType()) {
197 slangAssert(false && "Unknown type cannot be exported");
198 return NULL;
199 }
200
201 clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
202 if (RD != NULL) {
203 RD = RD->getDefinition();
204 if (RD == NULL) {
205 ReportTypeError(DiagEngine, NULL, T->getAsStructureType()->getDecl(),
206 "struct is not defined in this module");
207 return NULL;
208 }
209 }
210
211 if (!TopLevelRecord) {
212 TopLevelRecord = RD;
213 }
214 if (RD->getName().empty()) {
215 ReportTypeError(DiagEngine, NULL, RD,
216 "anonymous structures cannot be exported");
217 return NULL;
218 }
219
220 // Fast check
221 if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
222 return NULL;
223
224 // Insert myself into checking set
225 SPS.insert(T);
226
227 // Check all element
228 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
229 FE = RD->field_end();
230 FI != FE;
231 FI++) {
232 const clang::FieldDecl *FD = *FI;
233 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
234 FT = GET_CANONICAL_TYPE(FT);
235
236 if (!TypeExportableHelper(FT, SPS, DiagEngine, VD, TopLevelRecord)) {
237 return NULL;
238 }
239
240 // We don't support bit fields yet
241 //
242 // TODO(zonr/srhines): allow bit fields of size 8, 16, 32
243 if (FD->isBitField()) {
244 if (DiagEngine) {
245 DiagEngine->Report(
246 clang::FullSourceLoc(FD->getLocation(),
247 DiagEngine->getSourceManager()),
248 DiagEngine->getCustomDiagID(
249 clang::DiagnosticsEngine::Error,
250 "bit fields are not able to be exported: '%0.%1'"))
251 << RD->getName()
252 << FD->getName();
253 }
254 return NULL;
255 }
256 }
257
258 return T;
259 }
260 case clang::Type::Pointer: {
261 if (TopLevelRecord) {
262 ReportTypeError(DiagEngine, VD, TopLevelRecord,
263 "structures containing pointers cannot be exported: '%0'");
264 return NULL;
265 }
266
267 const clang::PointerType *PT =
268 UNSAFE_CAST_TYPE(const clang::PointerType, T);
269 const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
270
271 if (PointeeType->getTypeClass() == clang::Type::Pointer) {
272 ReportTypeError(DiagEngine, VD, TopLevelRecord,
273 "multiple levels of pointers cannot be exported: '%0'");
274 return NULL;
275 }
276 // We don't support pointer with array-type pointee or unsupported pointee
277 // type
278 if (PointeeType->isArrayType() ||
279 (TypeExportableHelper(PointeeType, SPS, DiagEngine, VD,
280 TopLevelRecord) == NULL))
281 return NULL;
282 else
283 return T;
284 }
285 case clang::Type::ExtVector: {
286 const clang::ExtVectorType *EVT =
287 UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
288 // Only vector with size 2, 3 and 4 are supported.
289 if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4)
290 return NULL;
291
292 // Check base element type
293 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
294
295 if ((ElementType->getTypeClass() != clang::Type::Builtin) ||
296 (TypeExportableHelper(ElementType, SPS, DiagEngine, VD,
297 TopLevelRecord) == NULL))
298 return NULL;
299 else
300 return T;
301 }
302 case clang::Type::ConstantArray: {
303 const clang::ConstantArrayType *CAT =
304 UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T);
305
306 return ConstantArrayTypeExportableHelper(CAT, SPS, DiagEngine, VD,
307 TopLevelRecord);
308 }
309 default: {
310 return NULL;
311 }
312 }
313 }
314
315 // Return the type that can be used to create RSExportType, will always return
316 // the canonical type
317 // If the Type T is not exportable, this function returns NULL. DiagEngine is
318 // used to generate proper Clang diagnostic messages when a
319 // non-exportable type is detected. TopLevelRecord is used to capture the
320 // highest struct (in the case of a nested hierarchy) for detecting other
321 // types that cannot be exported (mostly pointers within a struct).
TypeExportable(const clang::Type * T,clang::DiagnosticsEngine * DiagEngine,const clang::VarDecl * VD)322 static const clang::Type *TypeExportable(const clang::Type *T,
323 clang::DiagnosticsEngine *DiagEngine,
324 const clang::VarDecl *VD) {
325 llvm::SmallPtrSet<const clang::Type*, 8> SPS =
326 llvm::SmallPtrSet<const clang::Type*, 8>();
327
328 return TypeExportableHelper(T, SPS, DiagEngine, VD, NULL);
329 }
330
ValidateRSObjectInVarDecl(clang::VarDecl * VD,bool InCompositeType,unsigned int TargetAPI)331 static bool ValidateRSObjectInVarDecl(clang::VarDecl *VD,
332 bool InCompositeType,
333 unsigned int TargetAPI) {
334 if (TargetAPI < SLANG_JB_TARGET_API) {
335 // Only if we are already in a composite type (like an array or structure).
336 if (InCompositeType) {
337 // Only if we are actually exported (i.e. non-static).
338 if (VD->hasLinkage() &&
339 (VD->getFormalLinkage() == clang::ExternalLinkage)) {
340 // Only if we are not a pointer to an object.
341 const clang::Type *T = GET_CANONICAL_TYPE(VD->getType().getTypePtr());
342 if (T->getTypeClass() != clang::Type::Pointer) {
343 clang::ASTContext &C = VD->getASTContext();
344 ReportTypeError(&C.getDiagnostics(), VD, NULL,
345 "arrays/structures containing RS object types "
346 "cannot be exported in target API < %1: '%0'",
347 SLANG_JB_TARGET_API);
348 return false;
349 }
350 }
351 }
352 }
353
354 return true;
355 }
356
357 // Helper function for ValidateType(). We do a recursive descent on the
358 // type hierarchy to ensure that we can properly export/handle the
359 // declaration.
360 // \return true if the variable declaration is valid,
361 // false if it is invalid (along with proper diagnostics).
362 //
363 // C - ASTContext (for diagnostics + builtin types).
364 // T - sub-type that we are validating.
365 // ND - (optional) top-level named declaration that we are validating.
366 // SPS - set of types we have already seen/validated.
367 // InCompositeType - true if we are within an outer composite type.
368 // UnionDecl - set if we are in a sub-type of a union.
369 // TargetAPI - target SDK API level.
370 // IsFilterscript - whether or not we are compiling for Filterscript
ValidateTypeHelper(clang::ASTContext & C,const clang::Type * & T,clang::NamedDecl * ND,clang::SourceLocation Loc,llvm::SmallPtrSet<const clang::Type *,8> & SPS,bool InCompositeType,clang::RecordDecl * UnionDecl,unsigned int TargetAPI,bool IsFilterscript)371 static bool ValidateTypeHelper(
372 clang::ASTContext &C,
373 const clang::Type *&T,
374 clang::NamedDecl *ND,
375 clang::SourceLocation Loc,
376 llvm::SmallPtrSet<const clang::Type*, 8>& SPS,
377 bool InCompositeType,
378 clang::RecordDecl *UnionDecl,
379 unsigned int TargetAPI,
380 bool IsFilterscript) {
381 if ((T = GET_CANONICAL_TYPE(T)) == NULL)
382 return true;
383
384 if (SPS.count(T))
385 return true;
386
387 switch (T->getTypeClass()) {
388 case clang::Type::Record: {
389 if (RSExportPrimitiveType::IsRSObjectType(T)) {
390 clang::VarDecl *VD = (ND ? llvm::dyn_cast<clang::VarDecl>(ND) : NULL);
391 if (VD && !ValidateRSObjectInVarDecl(VD, InCompositeType, TargetAPI)) {
392 return false;
393 }
394 }
395
396 if (RSExportPrimitiveType::GetRSSpecificType(T) !=
397 RSExportPrimitiveType::DataTypeUnknown) {
398 if (!UnionDecl) {
399 return true;
400 } else if (RSExportPrimitiveType::IsRSObjectType(T)) {
401 ReportTypeError(&C.getDiagnostics(), NULL, UnionDecl,
402 "unions containing RS object types are not allowed");
403 return false;
404 }
405 }
406
407 clang::RecordDecl *RD = NULL;
408
409 // Check internal struct
410 if (T->isUnionType()) {
411 RD = T->getAsUnionType()->getDecl();
412 UnionDecl = RD;
413 } else if (T->isStructureType()) {
414 RD = T->getAsStructureType()->getDecl();
415 } else {
416 slangAssert(false && "Unknown type cannot be exported");
417 return false;
418 }
419
420 if (RD != NULL) {
421 RD = RD->getDefinition();
422 if (RD == NULL) {
423 // FIXME
424 return true;
425 }
426 }
427
428 // Fast check
429 if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
430 return false;
431
432 // Insert myself into checking set
433 SPS.insert(T);
434
435 // Check all elements
436 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
437 FE = RD->field_end();
438 FI != FE;
439 FI++) {
440 const clang::FieldDecl *FD = *FI;
441 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
442 FT = GET_CANONICAL_TYPE(FT);
443
444 if (!ValidateTypeHelper(C, FT, ND, Loc, SPS, true, UnionDecl,
445 TargetAPI, IsFilterscript)) {
446 return false;
447 }
448 }
449
450 return true;
451 }
452
453 case clang::Type::Builtin: {
454 if (IsFilterscript) {
455 clang::QualType QT = T->getCanonicalTypeInternal();
456 if (QT == C.DoubleTy ||
457 QT == C.LongDoubleTy ||
458 QT == C.LongTy ||
459 QT == C.LongLongTy) {
460 clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
461 if (ND) {
462 DiagEngine.Report(
463 clang::FullSourceLoc(Loc, C.getSourceManager()),
464 DiagEngine.getCustomDiagID(
465 clang::DiagnosticsEngine::Error,
466 "Builtin types > 32 bits in size are forbidden in "
467 "Filterscript: '%0'")) << ND->getName();
468 } else {
469 DiagEngine.Report(
470 clang::FullSourceLoc(Loc, C.getSourceManager()),
471 DiagEngine.getCustomDiagID(
472 clang::DiagnosticsEngine::Error,
473 "Builtin types > 32 bits in size are forbidden in "
474 "Filterscript"));
475 }
476 return false;
477 }
478 }
479 break;
480 }
481
482 case clang::Type::Pointer: {
483 if (IsFilterscript) {
484 if (ND) {
485 clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
486 DiagEngine.Report(
487 clang::FullSourceLoc(Loc, C.getSourceManager()),
488 DiagEngine.getCustomDiagID(
489 clang::DiagnosticsEngine::Error,
490 "Pointers are forbidden in Filterscript: '%0'")) << ND->getName();
491 return false;
492 } else {
493 // TODO(srhines): Find a better way to handle expressions (i.e. no
494 // NamedDecl) involving pointers in FS that should be allowed.
495 // An example would be calls to library functions like
496 // rsMatrixMultiply() that take rs_matrixNxN * types.
497 }
498 }
499
500 const clang::PointerType *PT =
501 UNSAFE_CAST_TYPE(const clang::PointerType, T);
502 const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
503
504 return ValidateTypeHelper(C, PointeeType, ND, Loc, SPS, InCompositeType,
505 UnionDecl, TargetAPI, IsFilterscript);
506 }
507
508 case clang::Type::ExtVector: {
509 const clang::ExtVectorType *EVT =
510 UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
511 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
512 if (TargetAPI < SLANG_ICS_TARGET_API &&
513 InCompositeType &&
514 EVT->getNumElements() == 3 &&
515 ND &&
516 ND->getFormalLinkage() == clang::ExternalLinkage) {
517 ReportTypeError(&C.getDiagnostics(), ND, NULL,
518 "structs containing vectors of dimension 3 cannot "
519 "be exported at this API level: '%0'");
520 return false;
521 }
522 return ValidateTypeHelper(C, ElementType, ND, Loc, SPS, true, UnionDecl,
523 TargetAPI, IsFilterscript);
524 }
525
526 case clang::Type::ConstantArray: {
527 const clang::ConstantArrayType *CAT =
528 UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T);
529 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
530 return ValidateTypeHelper(C, ElementType, ND, Loc, SPS, true, UnionDecl,
531 TargetAPI, IsFilterscript);
532 }
533
534 default: {
535 break;
536 }
537 }
538
539 return true;
540 }
541
542 } // namespace
543
544 /****************************** RSExportType ******************************/
NormalizeType(const clang::Type * & T,llvm::StringRef & TypeName,clang::DiagnosticsEngine * DiagEngine,const clang::VarDecl * VD)545 bool RSExportType::NormalizeType(const clang::Type *&T,
546 llvm::StringRef &TypeName,
547 clang::DiagnosticsEngine *DiagEngine,
548 const clang::VarDecl *VD) {
549 if ((T = TypeExportable(T, DiagEngine, VD)) == NULL) {
550 return false;
551 }
552 // Get type name
553 TypeName = RSExportType::GetTypeName(T);
554 if (TypeName.empty()) {
555 if (DiagEngine) {
556 if (VD) {
557 DiagEngine->Report(
558 clang::FullSourceLoc(VD->getLocation(),
559 DiagEngine->getSourceManager()),
560 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
561 "anonymous types cannot be exported"));
562 } else {
563 DiagEngine->Report(
564 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
565 "anonymous types cannot be exported"));
566 }
567 }
568 return false;
569 }
570
571 return true;
572 }
573
ValidateType(clang::ASTContext & C,clang::QualType QT,clang::NamedDecl * ND,clang::SourceLocation Loc,unsigned int TargetAPI,bool IsFilterscript)574 bool RSExportType::ValidateType(clang::ASTContext &C, clang::QualType QT,
575 clang::NamedDecl *ND, clang::SourceLocation Loc, unsigned int TargetAPI,
576 bool IsFilterscript) {
577 const clang::Type *T = QT.getTypePtr();
578 llvm::SmallPtrSet<const clang::Type*, 8> SPS =
579 llvm::SmallPtrSet<const clang::Type*, 8>();
580
581 return ValidateTypeHelper(C, T, ND, Loc, SPS, false, NULL, TargetAPI,
582 IsFilterscript);
583 return true;
584 }
585
ValidateVarDecl(clang::VarDecl * VD,unsigned int TargetAPI,bool IsFilterscript)586 bool RSExportType::ValidateVarDecl(clang::VarDecl *VD, unsigned int TargetAPI,
587 bool IsFilterscript) {
588 return ValidateType(VD->getASTContext(), VD->getType(), VD,
589 VD->getLocation(), TargetAPI, IsFilterscript);
590 }
591
592 const clang::Type
GetTypeOfDecl(const clang::DeclaratorDecl * DD)593 *RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
594 if (DD) {
595 clang::QualType T = DD->getType();
596
597 if (T.isNull())
598 return NULL;
599 else
600 return T.getTypePtr();
601 }
602 return NULL;
603 }
604
GetTypeName(const clang::Type * T)605 llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
606 T = GET_CANONICAL_TYPE(T);
607 if (T == NULL)
608 return llvm::StringRef();
609
610 switch (T->getTypeClass()) {
611 case clang::Type::Builtin: {
612 const clang::BuiltinType *BT =
613 UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
614
615 switch (BT->getKind()) {
616 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname) \
617 case builtin_type: \
618 return cname; \
619 break;
620 #include "RSClangBuiltinEnums.inc"
621 default: {
622 slangAssert(false && "Unknown data type of the builtin");
623 break;
624 }
625 }
626 break;
627 }
628 case clang::Type::Record: {
629 clang::RecordDecl *RD;
630 if (T->isStructureType()) {
631 RD = T->getAsStructureType()->getDecl();
632 } else {
633 break;
634 }
635
636 llvm::StringRef Name = RD->getName();
637 if (Name.empty()) {
638 if (RD->getTypedefNameForAnonDecl() != NULL) {
639 Name = RD->getTypedefNameForAnonDecl()->getName();
640 }
641
642 if (Name.empty()) {
643 // Try to find a name from redeclaration (i.e. typedef)
644 for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(),
645 RE = RD->redecls_end();
646 RI != RE;
647 RI++) {
648 slangAssert(*RI != NULL && "cannot be NULL object");
649
650 Name = (*RI)->getName();
651 if (!Name.empty())
652 break;
653 }
654 }
655 }
656 return Name;
657 }
658 case clang::Type::Pointer: {
659 // "*" plus pointee name
660 const clang::Type *PT = GET_POINTEE_TYPE(T);
661 llvm::StringRef PointeeName;
662 if (NormalizeType(PT, PointeeName, NULL, NULL)) {
663 char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
664 Name[0] = '*';
665 memcpy(Name + 1, PointeeName.data(), PointeeName.size());
666 Name[PointeeName.size() + 1] = '\0';
667 return Name;
668 }
669 break;
670 }
671 case clang::Type::ExtVector: {
672 const clang::ExtVectorType *EVT =
673 UNSAFE_CAST_TYPE(const clang::ExtVectorType, T);
674 return RSExportVectorType::GetTypeName(EVT);
675 break;
676 }
677 case clang::Type::ConstantArray : {
678 // Construct name for a constant array is too complicated.
679 return DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE;
680 }
681 default: {
682 break;
683 }
684 }
685
686 return llvm::StringRef();
687 }
688
689
Create(RSContext * Context,const clang::Type * T,const llvm::StringRef & TypeName)690 RSExportType *RSExportType::Create(RSContext *Context,
691 const clang::Type *T,
692 const llvm::StringRef &TypeName) {
693 // Lookup the context to see whether the type was processed before.
694 // Newly created RSExportType will insert into context
695 // in RSExportType::RSExportType()
696 RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
697
698 if (ETI != Context->export_types_end())
699 return ETI->second;
700
701 RSExportType *ET = NULL;
702 switch (T->getTypeClass()) {
703 case clang::Type::Record: {
704 RSExportPrimitiveType::DataType dt =
705 RSExportPrimitiveType::GetRSSpecificType(TypeName);
706 switch (dt) {
707 case RSExportPrimitiveType::DataTypeUnknown: {
708 // User-defined types
709 ET = RSExportRecordType::Create(Context,
710 T->getAsStructureType(),
711 TypeName);
712 break;
713 }
714 case RSExportPrimitiveType::DataTypeRSMatrix2x2: {
715 // 2 x 2 Matrix type
716 ET = RSExportMatrixType::Create(Context,
717 T->getAsStructureType(),
718 TypeName,
719 2);
720 break;
721 }
722 case RSExportPrimitiveType::DataTypeRSMatrix3x3: {
723 // 3 x 3 Matrix type
724 ET = RSExportMatrixType::Create(Context,
725 T->getAsStructureType(),
726 TypeName,
727 3);
728 break;
729 }
730 case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
731 // 4 x 4 Matrix type
732 ET = RSExportMatrixType::Create(Context,
733 T->getAsStructureType(),
734 TypeName,
735 4);
736 break;
737 }
738 default: {
739 // Others are primitive types
740 ET = RSExportPrimitiveType::Create(Context, T, TypeName);
741 break;
742 }
743 }
744 break;
745 }
746 case clang::Type::Builtin: {
747 ET = RSExportPrimitiveType::Create(Context, T, TypeName);
748 break;
749 }
750 case clang::Type::Pointer: {
751 ET = RSExportPointerType::Create(Context,
752 UNSAFE_CAST_TYPE(const clang::PointerType, T), TypeName);
753 // FIXME: free the name (allocated in RSExportType::GetTypeName)
754 delete [] TypeName.data();
755 break;
756 }
757 case clang::Type::ExtVector: {
758 ET = RSExportVectorType::Create(Context,
759 UNSAFE_CAST_TYPE(const clang::ExtVectorType, T), TypeName);
760 break;
761 }
762 case clang::Type::ConstantArray: {
763 ET = RSExportConstantArrayType::Create(
764 Context,
765 UNSAFE_CAST_TYPE(const clang::ConstantArrayType, T));
766 break;
767 }
768 default: {
769 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
770 DiagEngine->Report(
771 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
772 "unknown type cannot be exported: '%0'"))
773 << T->getTypeClassName();
774 break;
775 }
776 }
777
778 return ET;
779 }
780
Create(RSContext * Context,const clang::Type * T)781 RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
782 llvm::StringRef TypeName;
783 if (NormalizeType(T, TypeName, Context->getDiagnostics(), NULL)) {
784 return Create(Context, T, TypeName);
785 } else {
786 return NULL;
787 }
788 }
789
CreateFromDecl(RSContext * Context,const clang::VarDecl * VD)790 RSExportType *RSExportType::CreateFromDecl(RSContext *Context,
791 const clang::VarDecl *VD) {
792 return RSExportType::Create(Context, GetTypeOfDecl(VD));
793 }
794
GetTypeStoreSize(const RSExportType * ET)795 size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) {
796 return ET->getRSContext()->getDataLayout()->getTypeStoreSize(
797 ET->getLLVMType());
798 }
799
GetTypeAllocSize(const RSExportType * ET)800 size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) {
801 if (ET->getClass() == RSExportType::ExportClassRecord)
802 return static_cast<const RSExportRecordType*>(ET)->getAllocSize();
803 else
804 return ET->getRSContext()->getDataLayout()->getTypeAllocSize(
805 ET->getLLVMType());
806 }
807
RSExportType(RSContext * Context,ExportClass Class,const llvm::StringRef & Name)808 RSExportType::RSExportType(RSContext *Context,
809 ExportClass Class,
810 const llvm::StringRef &Name)
811 : RSExportable(Context, RSExportable::EX_TYPE),
812 mClass(Class),
813 // Make a copy on Name since memory stored @Name is either allocated in
814 // ASTContext or allocated in GetTypeName which will be destroyed later.
815 mName(Name.data(), Name.size()),
816 mLLVMType(NULL),
817 mSpecType(NULL) {
818 // Don't cache the type whose name start with '<'. Those type failed to
819 // get their name since constructing their name in GetTypeName() requiring
820 // complicated work.
821 if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX))
822 // TODO(zonr): Need to check whether the insertion is successful or not.
823 Context->insertExportType(llvm::StringRef(Name), this);
824 return;
825 }
826
keep()827 bool RSExportType::keep() {
828 if (!RSExportable::keep())
829 return false;
830 // Invalidate converted LLVM type.
831 mLLVMType = NULL;
832 return true;
833 }
834
equals(const RSExportable * E) const835 bool RSExportType::equals(const RSExportable *E) const {
836 CHECK_PARENT_EQUALITY(RSExportable, E);
837 return (static_cast<const RSExportType*>(E)->getClass() == getClass());
838 }
839
~RSExportType()840 RSExportType::~RSExportType() {
841 delete mSpecType;
842 }
843
844 /************************** RSExportPrimitiveType **************************/
845 llvm::ManagedStatic<RSExportPrimitiveType::RSSpecificTypeMapTy>
846 RSExportPrimitiveType::RSSpecificTypeMap;
847
848 llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL;
849
IsPrimitiveType(const clang::Type * T)850 bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
851 if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin))
852 return true;
853 else
854 return false;
855 }
856
857 RSExportPrimitiveType::DataType
GetRSSpecificType(const llvm::StringRef & TypeName)858 RSExportPrimitiveType::GetRSSpecificType(const llvm::StringRef &TypeName) {
859 if (TypeName.empty())
860 return DataTypeUnknown;
861
862 if (RSSpecificTypeMap->empty()) {
863 #define ENUM_RS_MATRIX_TYPE(type, cname, dim) \
864 RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
865 #include "RSMatrixTypeEnums.inc"
866 #define ENUM_RS_OBJECT_TYPE(type, cname) \
867 RSSpecificTypeMap->GetOrCreateValue(cname, DataType ## type);
868 #include "RSObjectTypeEnums.inc"
869 }
870
871 RSSpecificTypeMapTy::const_iterator I = RSSpecificTypeMap->find(TypeName);
872 if (I == RSSpecificTypeMap->end())
873 return DataTypeUnknown;
874 else
875 return I->getValue();
876 }
877
878 RSExportPrimitiveType::DataType
GetRSSpecificType(const clang::Type * T)879 RSExportPrimitiveType::GetRSSpecificType(const clang::Type *T) {
880 T = GET_CANONICAL_TYPE(T);
881 if ((T == NULL) || (T->getTypeClass() != clang::Type::Record))
882 return DataTypeUnknown;
883
884 return GetRSSpecificType( RSExportType::GetTypeName(T) );
885 }
886
IsRSMatrixType(DataType DT)887 bool RSExportPrimitiveType::IsRSMatrixType(DataType DT) {
888 return ((DT >= FirstRSMatrixType) && (DT <= LastRSMatrixType));
889 }
890
IsRSObjectType(DataType DT)891 bool RSExportPrimitiveType::IsRSObjectType(DataType DT) {
892 return ((DT >= FirstRSObjectType) && (DT <= LastRSObjectType));
893 }
894
IsStructureTypeWithRSObject(const clang::Type * T)895 bool RSExportPrimitiveType::IsStructureTypeWithRSObject(const clang::Type *T) {
896 bool RSObjectTypeSeen = false;
897 while (T && T->isArrayType()) {
898 T = T->getArrayElementTypeNoTypeQual();
899 }
900
901 const clang::RecordType *RT = T->getAsStructureType();
902 if (!RT) {
903 return false;
904 }
905
906 const clang::RecordDecl *RD = RT->getDecl();
907 if (RD) {
908 RD = RD->getDefinition();
909 }
910 if (!RD) {
911 return false;
912 }
913
914 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
915 FE = RD->field_end();
916 FI != FE;
917 FI++) {
918 // We just look through all field declarations to see if we find a
919 // declaration for an RS object type (or an array of one).
920 const clang::FieldDecl *FD = *FI;
921 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
922 while (FT && FT->isArrayType()) {
923 FT = FT->getArrayElementTypeNoTypeQual();
924 }
925
926 RSExportPrimitiveType::DataType DT = GetRSSpecificType(FT);
927 if (IsRSObjectType(DT)) {
928 // RS object types definitely need to be zero-initialized
929 RSObjectTypeSeen = true;
930 } else {
931 switch (DT) {
932 case RSExportPrimitiveType::DataTypeRSMatrix2x2:
933 case RSExportPrimitiveType::DataTypeRSMatrix3x3:
934 case RSExportPrimitiveType::DataTypeRSMatrix4x4:
935 // Matrix types should get zero-initialized as well
936 RSObjectTypeSeen = true;
937 break;
938 default:
939 // Ignore all other primitive types
940 break;
941 }
942 while (FT && FT->isArrayType()) {
943 FT = FT->getArrayElementTypeNoTypeQual();
944 }
945 if (FT->isStructureType()) {
946 // Recursively handle structs of structs (even though these can't
947 // be exported, it is possible for a user to have them internally).
948 RSObjectTypeSeen |= IsStructureTypeWithRSObject(FT);
949 }
950 }
951 }
952
953 return RSObjectTypeSeen;
954 }
955
956 const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[] = {
957 #define ENUM_RS_DATA_TYPE(type, cname, bits) \
958 bits,
959 #include "RSDataTypeEnums.inc"
960 0 // DataTypeMax
961 };
962
GetSizeInBits(const RSExportPrimitiveType * EPT)963 size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
964 slangAssert(((EPT->getType() > DataTypeUnknown) &&
965 (EPT->getType() < DataTypeMax)) &&
966 "RSExportPrimitiveType::GetSizeInBits : unknown data type");
967 return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ];
968 }
969
970 RSExportPrimitiveType::DataType
GetDataType(RSContext * Context,const clang::Type * T)971 RSExportPrimitiveType::GetDataType(RSContext *Context, const clang::Type *T) {
972 if (T == NULL)
973 return DataTypeUnknown;
974
975 switch (T->getTypeClass()) {
976 case clang::Type::Builtin: {
977 const clang::BuiltinType *BT =
978 UNSAFE_CAST_TYPE(const clang::BuiltinType, T);
979 switch (BT->getKind()) {
980 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname) \
981 case builtin_type: { \
982 return DataType ## type; \
983 }
984 #include "RSClangBuiltinEnums.inc"
985 // The size of type WChar depend on platform so we abandon the support
986 // to them.
987 default: {
988 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
989 DiagEngine->Report(
990 DiagEngine->getCustomDiagID(
991 clang::DiagnosticsEngine::Error,
992 "built-in type cannot be exported: '%0'"))
993 << T->getTypeClassName();
994 break;
995 }
996 }
997 break;
998 }
999 case clang::Type::Record: {
1000 // must be RS object type
1001 return RSExportPrimitiveType::GetRSSpecificType(T);
1002 }
1003 default: {
1004 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
1005 DiagEngine->Report(
1006 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1007 "primitive type cannot be exported: '%0'"))
1008 << T->getTypeClassName();
1009 break;
1010 }
1011 }
1012
1013 return DataTypeUnknown;
1014 }
1015
1016 RSExportPrimitiveType
Create(RSContext * Context,const clang::Type * T,const llvm::StringRef & TypeName,bool Normalized)1017 *RSExportPrimitiveType::Create(RSContext *Context,
1018 const clang::Type *T,
1019 const llvm::StringRef &TypeName,
1020 bool Normalized) {
1021 DataType DT = GetDataType(Context, T);
1022
1023 if ((DT == DataTypeUnknown) || TypeName.empty())
1024 return NULL;
1025 else
1026 return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
1027 DT, Normalized);
1028 }
1029
Create(RSContext * Context,const clang::Type * T)1030 RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
1031 const clang::Type *T) {
1032 llvm::StringRef TypeName;
1033 if (RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(), NULL)
1034 && IsPrimitiveType(T)) {
1035 return Create(Context, T, TypeName);
1036 } else {
1037 return NULL;
1038 }
1039 }
1040
convertToLLVMType() const1041 llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
1042 llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1043
1044 if (isRSObjectType()) {
1045 // struct {
1046 // int *p;
1047 // } __attribute__((packed, aligned(pointer_size)))
1048 //
1049 // which is
1050 //
1051 // <{ [1 x i32] }> in LLVM
1052 //
1053 if (RSObjectLLVMType == NULL) {
1054 std::vector<llvm::Type *> Elements;
1055 Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1));
1056 RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
1057 }
1058 return RSObjectLLVMType;
1059 }
1060
1061 switch (mType) {
1062 case DataTypeFloat32: {
1063 return llvm::Type::getFloatTy(C);
1064 break;
1065 }
1066 case DataTypeFloat64: {
1067 return llvm::Type::getDoubleTy(C);
1068 break;
1069 }
1070 case DataTypeBoolean: {
1071 return llvm::Type::getInt1Ty(C);
1072 break;
1073 }
1074 case DataTypeSigned8:
1075 case DataTypeUnsigned8: {
1076 return llvm::Type::getInt8Ty(C);
1077 break;
1078 }
1079 case DataTypeSigned16:
1080 case DataTypeUnsigned16:
1081 case DataTypeUnsigned565:
1082 case DataTypeUnsigned5551:
1083 case DataTypeUnsigned4444: {
1084 return llvm::Type::getInt16Ty(C);
1085 break;
1086 }
1087 case DataTypeSigned32:
1088 case DataTypeUnsigned32: {
1089 return llvm::Type::getInt32Ty(C);
1090 break;
1091 }
1092 case DataTypeSigned64:
1093 case DataTypeUnsigned64: {
1094 return llvm::Type::getInt64Ty(C);
1095 break;
1096 }
1097 default: {
1098 slangAssert(false && "Unknown data type");
1099 }
1100 }
1101
1102 return NULL;
1103 }
1104
convertToSpecType() const1105 union RSType *RSExportPrimitiveType::convertToSpecType() const {
1106 llvm::OwningPtr<union RSType> ST(new union RSType);
1107 RS_TYPE_SET_CLASS(ST, RS_TC_Primitive);
1108 // enum RSExportPrimitiveType::DataType is synced with enum RSDataType in
1109 // slang_rs_type_spec.h
1110 RS_PRIMITIVE_TYPE_SET_DATA_TYPE(ST, getType());
1111 return ST.take();
1112 }
1113
equals(const RSExportable * E) const1114 bool RSExportPrimitiveType::equals(const RSExportable *E) const {
1115 CHECK_PARENT_EQUALITY(RSExportType, E);
1116 return (static_cast<const RSExportPrimitiveType*>(E)->getType() == getType());
1117 }
1118
getRSReflectionType(DataType DT)1119 RSReflectionType *RSExportPrimitiveType::getRSReflectionType(DataType DT) {
1120 if (DT > DataTypeUnknown && DT < DataTypeMax) {
1121 return &gReflectionTypes[DT];
1122 } else {
1123 return NULL;
1124 }
1125 }
1126
1127 /**************************** RSExportPointerType ****************************/
1128
1129 RSExportPointerType
Create(RSContext * Context,const clang::PointerType * PT,const llvm::StringRef & TypeName)1130 *RSExportPointerType::Create(RSContext *Context,
1131 const clang::PointerType *PT,
1132 const llvm::StringRef &TypeName) {
1133 const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
1134 const RSExportType *PointeeET;
1135
1136 if (PointeeType->getTypeClass() != clang::Type::Pointer) {
1137 PointeeET = RSExportType::Create(Context, PointeeType);
1138 } else {
1139 // Double or higher dimension of pointer, export as int*
1140 PointeeET = RSExportPrimitiveType::Create(Context,
1141 Context->getASTContext().IntTy.getTypePtr());
1142 }
1143
1144 if (PointeeET == NULL) {
1145 // Error diagnostic is emitted for corresponding pointee type
1146 return NULL;
1147 }
1148
1149 return new RSExportPointerType(Context, TypeName, PointeeET);
1150 }
1151
convertToLLVMType() const1152 llvm::Type *RSExportPointerType::convertToLLVMType() const {
1153 llvm::Type *PointeeType = mPointeeType->getLLVMType();
1154 return llvm::PointerType::getUnqual(PointeeType);
1155 }
1156
convertToSpecType() const1157 union RSType *RSExportPointerType::convertToSpecType() const {
1158 llvm::OwningPtr<union RSType> ST(new union RSType);
1159
1160 RS_TYPE_SET_CLASS(ST, RS_TC_Pointer);
1161 RS_POINTER_TYPE_SET_POINTEE_TYPE(ST, getPointeeType()->getSpecType());
1162
1163 if (RS_POINTER_TYPE_GET_POINTEE_TYPE(ST) != NULL)
1164 return ST.take();
1165 else
1166 return NULL;
1167 }
1168
keep()1169 bool RSExportPointerType::keep() {
1170 if (!RSExportType::keep())
1171 return false;
1172 const_cast<RSExportType*>(mPointeeType)->keep();
1173 return true;
1174 }
1175
equals(const RSExportable * E) const1176 bool RSExportPointerType::equals(const RSExportable *E) const {
1177 CHECK_PARENT_EQUALITY(RSExportType, E);
1178 return (static_cast<const RSExportPointerType*>(E)
1179 ->getPointeeType()->equals(getPointeeType()));
1180 }
1181
1182 /***************************** RSExportVectorType *****************************/
1183 llvm::StringRef
GetTypeName(const clang::ExtVectorType * EVT)1184 RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
1185 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
1186
1187 if ((ElementType->getTypeClass() != clang::Type::Builtin))
1188 return llvm::StringRef();
1189
1190 const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(const clang::BuiltinType,
1191 ElementType);
1192 if ((EVT->getNumElements() < 1) ||
1193 (EVT->getNumElements() > 4))
1194 return llvm::StringRef();
1195
1196 switch (BT->getKind()) {
1197 // Compiler is smart enough to optimize following *big if branches* since
1198 // they all become "constant comparison" after macro expansion
1199 #define ENUM_SUPPORT_BUILTIN_TYPE(builtin_type, type, cname) \
1200 case builtin_type: { \
1201 const char *Name[] = { cname"2", cname"3", cname"4" }; \
1202 return Name[EVT->getNumElements() - 2]; \
1203 break; \
1204 }
1205 #include "RSClangBuiltinEnums.inc"
1206 default: {
1207 return llvm::StringRef();
1208 }
1209 }
1210 }
1211
Create(RSContext * Context,const clang::ExtVectorType * EVT,const llvm::StringRef & TypeName,bool Normalized)1212 RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
1213 const clang::ExtVectorType *EVT,
1214 const llvm::StringRef &TypeName,
1215 bool Normalized) {
1216 slangAssert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector);
1217
1218 const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
1219 RSExportPrimitiveType::DataType DT =
1220 RSExportPrimitiveType::GetDataType(Context, ElementType);
1221
1222 if (DT != RSExportPrimitiveType::DataTypeUnknown)
1223 return new RSExportVectorType(Context,
1224 TypeName,
1225 DT,
1226 Normalized,
1227 EVT->getNumElements());
1228 else
1229 return NULL;
1230 }
1231
convertToLLVMType() const1232 llvm::Type *RSExportVectorType::convertToLLVMType() const {
1233 llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType();
1234 return llvm::VectorType::get(ElementType, getNumElement());
1235 }
1236
convertToSpecType() const1237 union RSType *RSExportVectorType::convertToSpecType() const {
1238 llvm::OwningPtr<union RSType> ST(new union RSType);
1239
1240 RS_TYPE_SET_CLASS(ST, RS_TC_Vector);
1241 RS_VECTOR_TYPE_SET_ELEMENT_TYPE(ST, getType());
1242 RS_VECTOR_TYPE_SET_VECTOR_SIZE(ST, getNumElement());
1243
1244 return ST.take();
1245 }
1246
equals(const RSExportable * E) const1247 bool RSExportVectorType::equals(const RSExportable *E) const {
1248 CHECK_PARENT_EQUALITY(RSExportPrimitiveType, E);
1249 return (static_cast<const RSExportVectorType*>(E)->getNumElement()
1250 == getNumElement());
1251 }
1252
1253 /***************************** RSExportMatrixType *****************************/
Create(RSContext * Context,const clang::RecordType * RT,const llvm::StringRef & TypeName,unsigned Dim)1254 RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context,
1255 const clang::RecordType *RT,
1256 const llvm::StringRef &TypeName,
1257 unsigned Dim) {
1258 slangAssert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record));
1259 slangAssert((Dim > 1) && "Invalid dimension of matrix");
1260
1261 // Check whether the struct rs_matrix is in our expected form (but assume it's
1262 // correct if we're not sure whether it's correct or not)
1263 const clang::RecordDecl* RD = RT->getDecl();
1264 RD = RD->getDefinition();
1265 if (RD != NULL) {
1266 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
1267 const clang::SourceManager *SM = Context->getSourceManager();
1268 // Find definition, perform further examination
1269 if (RD->field_empty()) {
1270 DiagEngine->Report(
1271 clang::FullSourceLoc(RD->getLocation(), *SM),
1272 DiagEngine->getCustomDiagID(
1273 clang::DiagnosticsEngine::Error,
1274 "invalid matrix struct: must have 1 field for saving values: '%0'"))
1275 << RD->getName();
1276 return NULL;
1277 }
1278
1279 clang::RecordDecl::field_iterator FIT = RD->field_begin();
1280 const clang::FieldDecl *FD = *FIT;
1281 const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
1282 if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
1283 DiagEngine->Report(
1284 clang::FullSourceLoc(RD->getLocation(), *SM),
1285 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1286 "invalid matrix struct: first field should"
1287 " be an array with constant size: '%0'"))
1288 << RD->getName();
1289 return NULL;
1290 }
1291 const clang::ConstantArrayType *CAT =
1292 static_cast<const clang::ConstantArrayType *>(FT);
1293 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1294 if ((ElementType == NULL) ||
1295 (ElementType->getTypeClass() != clang::Type::Builtin) ||
1296 (static_cast<const clang::BuiltinType *>(ElementType)->getKind() !=
1297 clang::BuiltinType::Float)) {
1298 DiagEngine->Report(
1299 clang::FullSourceLoc(RD->getLocation(), *SM),
1300 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1301 "invalid matrix struct: first field "
1302 "should be a float array: '%0'"))
1303 << RD->getName();
1304 return NULL;
1305 }
1306
1307 if (CAT->getSize() != Dim * Dim) {
1308 DiagEngine->Report(
1309 clang::FullSourceLoc(RD->getLocation(), *SM),
1310 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1311 "invalid matrix struct: first field "
1312 "should be an array with size %0: '%1'"))
1313 << (Dim * Dim) << (RD->getName());
1314 return NULL;
1315 }
1316
1317 FIT++;
1318 if (FIT != RD->field_end()) {
1319 DiagEngine->Report(
1320 clang::FullSourceLoc(RD->getLocation(), *SM),
1321 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1322 "invalid matrix struct: must have "
1323 "exactly 1 field: '%0'"))
1324 << RD->getName();
1325 return NULL;
1326 }
1327 }
1328
1329 return new RSExportMatrixType(Context, TypeName, Dim);
1330 }
1331
convertToLLVMType() const1332 llvm::Type *RSExportMatrixType::convertToLLVMType() const {
1333 // Construct LLVM type:
1334 // struct {
1335 // float X[mDim * mDim];
1336 // }
1337
1338 llvm::LLVMContext &C = getRSContext()->getLLVMContext();
1339 llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C),
1340 mDim * mDim);
1341 return llvm::StructType::get(C, X, false);
1342 }
1343
convertToSpecType() const1344 union RSType *RSExportMatrixType::convertToSpecType() const {
1345 llvm::OwningPtr<union RSType> ST(new union RSType);
1346 RS_TYPE_SET_CLASS(ST, RS_TC_Matrix);
1347 switch (getDim()) {
1348 case 2: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix2x2); break;
1349 case 3: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix3x3); break;
1350 case 4: RS_MATRIX_TYPE_SET_DATA_TYPE(ST, RS_DT_RSMatrix4x4); break;
1351 default: slangAssert(false && "Matrix type with unsupported dimension.");
1352 }
1353 return ST.take();
1354 }
1355
equals(const RSExportable * E) const1356 bool RSExportMatrixType::equals(const RSExportable *E) const {
1357 CHECK_PARENT_EQUALITY(RSExportType, E);
1358 return (static_cast<const RSExportMatrixType*>(E)->getDim() == getDim());
1359 }
1360
1361 /************************* RSExportConstantArrayType *************************/
1362 RSExportConstantArrayType
Create(RSContext * Context,const clang::ConstantArrayType * CAT)1363 *RSExportConstantArrayType::Create(RSContext *Context,
1364 const clang::ConstantArrayType *CAT) {
1365 slangAssert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray);
1366
1367 slangAssert((CAT->getSize().getActiveBits() < 32) && "array too large");
1368
1369 unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue());
1370 slangAssert((Size > 0) && "Constant array should have size greater than 0");
1371
1372 const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
1373 RSExportType *ElementET = RSExportType::Create(Context, ElementType);
1374
1375 if (ElementET == NULL) {
1376 return NULL;
1377 }
1378
1379 return new RSExportConstantArrayType(Context,
1380 ElementET,
1381 Size);
1382 }
1383
convertToLLVMType() const1384 llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
1385 return llvm::ArrayType::get(mElementType->getLLVMType(), getSize());
1386 }
1387
convertToSpecType() const1388 union RSType *RSExportConstantArrayType::convertToSpecType() const {
1389 llvm::OwningPtr<union RSType> ST(new union RSType);
1390
1391 RS_TYPE_SET_CLASS(ST, RS_TC_ConstantArray);
1392 RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_TYPE(
1393 ST, getElementType()->getSpecType());
1394 RS_CONSTANT_ARRAY_TYPE_SET_ELEMENT_SIZE(ST, getSize());
1395
1396 if (RS_CONSTANT_ARRAY_TYPE_GET_ELEMENT_TYPE(ST) != NULL)
1397 return ST.take();
1398 else
1399 return NULL;
1400 }
1401
keep()1402 bool RSExportConstantArrayType::keep() {
1403 if (!RSExportType::keep())
1404 return false;
1405 const_cast<RSExportType*>(mElementType)->keep();
1406 return true;
1407 }
1408
equals(const RSExportable * E) const1409 bool RSExportConstantArrayType::equals(const RSExportable *E) const {
1410 CHECK_PARENT_EQUALITY(RSExportType, E);
1411 const RSExportConstantArrayType *RHS =
1412 static_cast<const RSExportConstantArrayType*>(E);
1413 return ((getSize() == RHS->getSize()) &&
1414 (getElementType()->equals(RHS->getElementType())));
1415 }
1416
1417 /**************************** RSExportRecordType ****************************/
Create(RSContext * Context,const clang::RecordType * RT,const llvm::StringRef & TypeName,bool mIsArtificial)1418 RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
1419 const clang::RecordType *RT,
1420 const llvm::StringRef &TypeName,
1421 bool mIsArtificial) {
1422 slangAssert(RT != NULL && RT->getTypeClass() == clang::Type::Record);
1423
1424 const clang::RecordDecl *RD = RT->getDecl();
1425 slangAssert(RD->isStruct());
1426
1427 RD = RD->getDefinition();
1428 if (RD == NULL) {
1429 slangAssert(false && "struct is not defined in this module");
1430 return NULL;
1431 }
1432
1433 // Struct layout construct by clang. We rely on this for obtaining the
1434 // alloc size of a struct and offset of every field in that struct.
1435 const clang::ASTRecordLayout *RL =
1436 &Context->getASTContext().getASTRecordLayout(RD);
1437 slangAssert((RL != NULL) &&
1438 "Failed to retrieve the struct layout from Clang.");
1439
1440 RSExportRecordType *ERT =
1441 new RSExportRecordType(Context,
1442 TypeName,
1443 RD->hasAttr<clang::PackedAttr>(),
1444 mIsArtificial,
1445 RL->getSize().getQuantity());
1446 unsigned int Index = 0;
1447
1448 for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
1449 FE = RD->field_end();
1450 FI != FE;
1451 FI++, Index++) {
1452 clang::DiagnosticsEngine *DiagEngine = Context->getDiagnostics();
1453
1454 // FIXME: All fields should be primitive type
1455 slangAssert(FI->getKind() == clang::Decl::Field);
1456 clang::FieldDecl *FD = *FI;
1457
1458 if (FD->isBitField()) {
1459 return NULL;
1460 }
1461
1462 // Type
1463 RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
1464
1465 if (ET != NULL) {
1466 ERT->mFields.push_back(
1467 new Field(ET, FD->getName(), ERT,
1468 static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
1469 } else {
1470 DiagEngine->Report(
1471 clang::FullSourceLoc(RD->getLocation(), DiagEngine->getSourceManager()),
1472 DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error,
1473 "field type cannot be exported: '%0.%1'"))
1474 << RD->getName() << FD->getName();
1475 return NULL;
1476 }
1477 }
1478
1479 return ERT;
1480 }
1481
convertToLLVMType() const1482 llvm::Type *RSExportRecordType::convertToLLVMType() const {
1483 // Create an opaque type since struct may reference itself recursively.
1484
1485 // TODO(sliao): LLVM took out the OpaqueType. Any other to migrate to?
1486 std::vector<llvm::Type*> FieldTypes;
1487
1488 for (const_field_iterator FI = fields_begin(), FE = fields_end();
1489 FI != FE;
1490 FI++) {
1491 const Field *F = *FI;
1492 const RSExportType *FET = F->getType();
1493
1494 FieldTypes.push_back(FET->getLLVMType());
1495 }
1496
1497 llvm::StructType *ST = llvm::StructType::get(getRSContext()->getLLVMContext(),
1498 FieldTypes,
1499 mIsPacked);
1500 if (ST != NULL) {
1501 return ST;
1502 } else {
1503 return NULL;
1504 }
1505 }
1506
convertToSpecType() const1507 union RSType *RSExportRecordType::convertToSpecType() const {
1508 unsigned NumFields = getFields().size();
1509 unsigned AllocSize = sizeof(union RSType) +
1510 sizeof(struct RSRecordField) * NumFields;
1511 llvm::OwningPtr<union RSType> ST(
1512 reinterpret_cast<union RSType*>(operator new(AllocSize)));
1513
1514 ::memset(ST.get(), 0, AllocSize);
1515
1516 RS_TYPE_SET_CLASS(ST, RS_TC_Record);
1517 RS_RECORD_TYPE_SET_NAME(ST, getName().c_str());
1518 RS_RECORD_TYPE_SET_NUM_FIELDS(ST, NumFields);
1519
1520 setSpecTypeTemporarily(ST.get());
1521
1522 unsigned FieldIdx = 0;
1523 for (const_field_iterator FI = fields_begin(), FE = fields_end();
1524 FI != FE;
1525 FI++, FieldIdx++) {
1526 const Field *F = *FI;
1527
1528 RS_RECORD_TYPE_SET_FIELD_NAME(ST, FieldIdx, F->getName().c_str());
1529 RS_RECORD_TYPE_SET_FIELD_TYPE(ST, FieldIdx, F->getType()->getSpecType());
1530 }
1531
1532 // TODO(slang): Check whether all fields were created normally.
1533
1534 return ST.take();
1535 }
1536
keep()1537 bool RSExportRecordType::keep() {
1538 if (!RSExportType::keep())
1539 return false;
1540 for (std::list<const Field*>::iterator I = mFields.begin(),
1541 E = mFields.end();
1542 I != E;
1543 I++) {
1544 const_cast<RSExportType*>((*I)->getType())->keep();
1545 }
1546 return true;
1547 }
1548
equals(const RSExportable * E) const1549 bool RSExportRecordType::equals(const RSExportable *E) const {
1550 CHECK_PARENT_EQUALITY(RSExportType, E);
1551
1552 const RSExportRecordType *ERT = static_cast<const RSExportRecordType*>(E);
1553
1554 if (ERT->getFields().size() != getFields().size())
1555 return false;
1556
1557 const_field_iterator AI = fields_begin(), BI = ERT->fields_begin();
1558
1559 for (unsigned i = 0, e = getFields().size(); i != e; i++) {
1560 if (!(*AI)->getType()->equals((*BI)->getType()))
1561 return false;
1562 AI++;
1563 BI++;
1564 }
1565
1566 return true;
1567 }
1568
convertToRTD(RSReflectionTypeData * rtd) const1569 void RSExportType::convertToRTD(RSReflectionTypeData *rtd) const {
1570 memset(rtd, 0, sizeof(*rtd));
1571 rtd->vecSize = 1;
1572
1573 switch(getClass()) {
1574 case RSExportType::ExportClassPrimitive: {
1575 const RSExportPrimitiveType *EPT = static_cast<const RSExportPrimitiveType*>(this);
1576 rtd->type = RSExportPrimitiveType::getRSReflectionType(EPT);
1577 return;
1578 }
1579 case RSExportType::ExportClassPointer: {
1580 const RSExportPointerType *EPT = static_cast<const RSExportPointerType*>(this);
1581 const RSExportType *PointeeType = EPT->getPointeeType();
1582 PointeeType->convertToRTD(rtd);
1583 rtd->isPointer = true;
1584 return;
1585 }
1586 case RSExportType::ExportClassVector: {
1587 const RSExportVectorType *EVT = static_cast<const RSExportVectorType*>(this);
1588 rtd->type = EVT->getRSReflectionType(EVT);
1589 rtd->vecSize = EVT->getNumElement();
1590 return;
1591 }
1592 case RSExportType::ExportClassMatrix: {
1593 const RSExportMatrixType *EMT = static_cast<const RSExportMatrixType*>(this);
1594 unsigned Dim = EMT->getDim();
1595 slangAssert((Dim >= 2) && (Dim <= 4));
1596 rtd->type = &gReflectionTypes[15 + Dim-2];
1597 return;
1598 }
1599 case RSExportType::ExportClassConstantArray: {
1600 const RSExportConstantArrayType* CAT =
1601 static_cast<const RSExportConstantArrayType*>(this);
1602 CAT->getElementType()->convertToRTD(rtd);
1603 rtd->arraySize = CAT->getSize();
1604 return;
1605 }
1606 case RSExportType::ExportClassRecord: {
1607 slangAssert(!"RSExportType::ExportClassRecord not implemented");
1608 return;// RS_TYPE_CLASS_NAME_PREFIX + ET->getName() + ".Item";
1609 }
1610 default: {
1611 slangAssert(false && "Unknown class of type");
1612 }
1613 }
1614 }
1615
1616
1617 } // namespace slang
1618