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