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