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