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