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