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