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