slang_rs_export_type.cpp revision a5d2c232d56b04292cb51c8fb343aef990f7970f
1#include "slang_rs_export_type.h"
2
3#include <vector>
4
5#include "llvm/Type.h"
6#include "llvm/DerivedTypes.h"
7
8#include "llvm/ADT/StringExtras.h"
9#include "llvm/Target/TargetData.h"
10
11#include "clang/AST/RecordLayout.h"
12
13#include "slang_rs_context.h"
14#include "slang_rs_export_element.h"
15
16using namespace slang;
17
18/****************************** RSExportType ******************************/
19bool RSExportType::NormalizeType(const clang::Type *&T,
20                                 llvm::StringRef &TypeName) {
21  llvm::SmallPtrSet<const clang::Type*, 8> SPS =
22      llvm::SmallPtrSet<const clang::Type*, 8>();
23
24  if ((T = RSExportType::TypeExportable(T, SPS)) == NULL)
25    // TODO(zonr): warn that type not exportable.
26    return false;
27
28  // Get type name
29  TypeName = RSExportType::GetTypeName(T);
30  if (TypeName.empty())
31    // TODO(zonr): warning that the type is unnamed.
32    return false;
33
34  return true;
35}
36
37const clang::Type
38*RSExportType::GetTypeOfDecl(const clang::DeclaratorDecl *DD) {
39  if (DD) {
40    clang::QualType T;
41    if (DD->getTypeSourceInfo())
42      T = DD->getTypeSourceInfo()->getType();
43    else
44      T = DD->getType();
45
46    if (T.isNull())
47      return NULL;
48    else
49      return T.getTypePtr();
50  }
51  return NULL;
52}
53
54llvm::StringRef RSExportType::GetTypeName(const clang::Type* T) {
55  T = GET_CANONICAL_TYPE(T);
56  if (T == NULL)
57    return llvm::StringRef();
58
59  switch (T->getTypeClass()) {
60    case clang::Type::Builtin: {
61      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
62
63      switch (BT->getKind()) {
64        // Compiler is smart enough to optimize following *big if branches*
65        // since they all become "constant comparison" after macro expansion
66#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type)       \
67        case builtin_type: {                                    \
68          if (type == RSExportPrimitiveType::DataTypeFloat32)           \
69            return "float";                                             \
70          else if (type == RSExportPrimitiveType::DataTypeFloat64)      \
71            return "double";                                            \
72          else if (type == RSExportPrimitiveType::DataTypeUnsigned8)    \
73            return "uchar";                                             \
74          else if (type == RSExportPrimitiveType::DataTypeUnsigned16)   \
75            return "ushort";                                            \
76          else if (type == RSExportPrimitiveType::DataTypeUnsigned32)   \
77            return "uint";                                              \
78          else if (type == RSExportPrimitiveType::DataTypeUnsigned64)   \
79            return "ulong";                                             \
80          else if (type == RSExportPrimitiveType::DataTypeSigned8)      \
81            return "char";                                              \
82          else if (type == RSExportPrimitiveType::DataTypeSigned16)     \
83            return "short";                                             \
84          else if (type == RSExportPrimitiveType::DataTypeSigned32)     \
85            return "int";                                               \
86          else if (type == RSExportPrimitiveType::DataTypeSigned64)     \
87            return "long";                                              \
88          else if (type == RSExportPrimitiveType::DataTypeBoolean)      \
89            return "bool";                                              \
90          else                                                          \
91            assert(false && "Unknow data type of supported builtin");   \
92          break;                                                        \
93        }
94#include "slang_rs_export_type_support.inc"
95
96          default: {
97            assert(false && "Unknown data type of the builtin");
98            break;
99          }
100        }
101      break;
102    }
103    case clang::Type::Record: {
104      const clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
105      llvm::StringRef Name = RD->getName();
106      if (Name.empty()) {
107          if (RD->getTypedefForAnonDecl() != NULL)
108            Name = RD->getTypedefForAnonDecl()->getName();
109
110          if (Name.empty())
111            // Try to find a name from redeclaration (i.e. typedef)
112            for (clang::TagDecl::redecl_iterator RI = RD->redecls_begin(),
113                     RE = RD->redecls_end();
114                 RI != RE;
115                 RI++) {
116              assert(*RI != NULL && "cannot be NULL object");
117
118              Name = (*RI)->getName();
119              if (!Name.empty())
120                break;
121            }
122      }
123      return Name;
124    }
125    case clang::Type::Pointer: {
126      // "*" plus pointee name
127      const clang::Type *PT = GET_POINTEE_TYPE(T);
128      llvm::StringRef PointeeName;
129      if (NormalizeType(PT, PointeeName)) {
130        char *Name = new char[ 1 /* * */ + PointeeName.size() + 1 ];
131        Name[0] = '*';
132        memcpy(Name + 1, PointeeName.data(), PointeeName.size());
133        Name[PointeeName.size() + 1] = '\0';
134        return Name;
135      }
136      break;
137    }
138    case clang::Type::ExtVector: {
139      const clang::ExtVectorType *EVT =
140          UNSAFE_CAST_TYPE(clang::ExtVectorType, T);
141      return RSExportVectorType::GetTypeName(EVT);
142      break;
143    }
144    case clang::Type::ConstantArray : {
145      // Construct name for a constant array is too complicated.
146      return DUMMY_TYPE_NAME_FOR_RS_CONSTANT_ARRAY_TYPE;
147    }
148    default: {
149      break;
150    }
151  }
152
153  return llvm::StringRef();
154}
155
156const clang::Type *RSExportType::TypeExportable(
157    const clang::Type *T,
158    llvm::SmallPtrSet<const clang::Type*, 8>& SPS) {
159  // Normalize first
160  if ((T = GET_CANONICAL_TYPE(T)) == NULL)
161    return NULL;
162
163  if (SPS.count(T))
164    return T;
165
166  switch (T->getTypeClass()) {
167    case clang::Type::Builtin: {
168      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
169
170      switch (BT->getKind()) {
171#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type)       \
172        case builtin_type:
173#include "slang_rs_export_type_support.inc"
174        {
175          return T;
176        }
177        default: {
178          return NULL;
179        }
180      }
181      // Never be here
182    }
183    case clang::Type::Record: {
184      if (RSExportPrimitiveType::GetRSObjectType(T) !=
185          RSExportPrimitiveType::DataTypeUnknown)
186        return T;  // RS object type, no further checks are needed
187
188      // Check internal struct
189      const clang::RecordDecl *RD = T->getAsStructureType()->getDecl();
190      if (RD != NULL)
191        RD = RD->getDefinition();
192
193      // Fast check
194      if (RD->hasFlexibleArrayMember() || RD->hasObjectMember())
195        return NULL;
196
197      // Insert myself into checking set
198      SPS.insert(T);
199
200      // Check all element
201      for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
202               FE = RD->field_end();
203           FI != FE;
204           FI++) {
205        const clang::FieldDecl *FD = *FI;
206        const clang::Type *FT = GetTypeOfDecl(FD);
207        FT = GET_CANONICAL_TYPE(FT);
208
209        if (!TypeExportable(FT, SPS)) {
210          fprintf(stderr, "Field `%s' in Record `%s' contains unsupported "
211                          "type\n", FD->getNameAsString().c_str(),
212                                    RD->getNameAsString().c_str());
213          FT->dump();
214          return NULL;
215        }
216      }
217
218      return T;
219    }
220    case clang::Type::Pointer: {
221      const clang::PointerType *PT = UNSAFE_CAST_TYPE(clang::PointerType, T);
222      const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
223
224      if (PointeeType->getTypeClass() == clang::Type::Pointer)
225        return T;
226      // We don't support pointer with array-type pointee or unsupported pointee
227      // type
228      if (PointeeType->isArrayType() ||
229         (TypeExportable(PointeeType, SPS) == NULL) )
230        return NULL;
231      else
232        return T;
233    }
234    case clang::Type::ExtVector: {
235      const clang::ExtVectorType *EVT =
236          UNSAFE_CAST_TYPE(clang::ExtVectorType, T);
237      // Only vector with size 2, 3 and 4 are supported.
238      if (EVT->getNumElements() < 2 || EVT->getNumElements() > 4)
239        return NULL;
240
241      // Check base element type
242      const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
243
244      if ((ElementType->getTypeClass() != clang::Type::Builtin) ||
245          (TypeExportable(ElementType, SPS) == NULL))
246        return NULL;
247      else
248        return T;
249    }
250    case clang::Type::ConstantArray: {
251      const clang::ConstantArrayType *CAT =
252          UNSAFE_CAST_TYPE(clang::ConstantArrayType, T);
253
254      // Check size
255      if (CAT->getSize().getActiveBits() > 32) {
256        fprintf(stderr, "RSExportConstantArrayType::Create : array with too "
257                        "large size (> 2^32).\n");
258        return NULL;
259      }
260      // Check element type
261      const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
262      if (ElementType->isArrayType()) {
263        fprintf(stderr, "RSExportType::TypeExportable : constant array with 2 "
264                        "or higher dimension of constant is not supported.\n");
265        return NULL;
266      }
267      if (TypeExportable(ElementType, SPS) == NULL)
268        return NULL;
269      else
270        return T;
271    }
272    default: {
273      return NULL;
274    }
275  }
276}
277
278RSExportType *RSExportType::Create(RSContext *Context,
279                                   const clang::Type *T,
280                                   const llvm::StringRef &TypeName) {
281  // Lookup the context to see whether the type was processed before.
282  // Newly created RSExportType will insert into context
283  // in RSExportType::RSExportType()
284  RSContext::export_type_iterator ETI = Context->findExportType(TypeName);
285
286  if (ETI != Context->export_types_end())
287    return ETI->second;
288
289  RSExportType *ET = NULL;
290  switch (T->getTypeClass()) {
291    case clang::Type::Record: {
292      RSExportPrimitiveType::DataType dt =
293          RSExportPrimitiveType::GetRSObjectType(TypeName);
294      switch (dt) {
295        case RSExportPrimitiveType::DataTypeUnknown: {
296          // User-defined types
297          ET = RSExportRecordType::Create(Context,
298                                          T->getAsStructureType(),
299                                          TypeName);
300          break;
301        }
302        case RSExportPrimitiveType::DataTypeRSMatrix2x2: {
303          // 2 x 2 Matrix type
304          ET = RSExportMatrixType::Create(Context,
305                                          T->getAsStructureType(),
306                                          TypeName,
307                                          2);
308          break;
309        }
310        case RSExportPrimitiveType::DataTypeRSMatrix3x3: {
311          // 3 x 3 Matrix type
312          ET = RSExportMatrixType::Create(Context,
313                                          T->getAsStructureType(),
314                                          TypeName,
315                                          3);
316          break;
317        }
318        case RSExportPrimitiveType::DataTypeRSMatrix4x4: {
319          // 4 x 4 Matrix type
320          ET = RSExportMatrixType::Create(Context,
321                                          T->getAsStructureType(),
322                                          TypeName,
323                                          4);
324          break;
325        }
326        default: {
327          // Others are primitive types
328          ET = RSExportPrimitiveType::Create(Context, T, TypeName);
329          break;
330        }
331      }
332      break;
333    }
334    case clang::Type::Builtin: {
335      ET = RSExportPrimitiveType::Create(Context, T, TypeName);
336      break;
337    }
338    case clang::Type::Pointer: {
339      ET = RSExportPointerType::Create(Context,
340                                       UNSAFE_CAST_TYPE(clang::PointerType, T),
341                                       TypeName);
342      // FIXME: free the name (allocated in RSExportType::GetTypeName)
343      delete [] TypeName.data();
344      break;
345    }
346    case clang::Type::ExtVector: {
347      ET = RSExportVectorType::Create(Context,
348                                      UNSAFE_CAST_TYPE(clang::ExtVectorType, T),
349                                      TypeName);
350      break;
351    }
352    case clang::Type::ConstantArray: {
353      ET = RSExportConstantArrayType::Create(
354              Context,
355              UNSAFE_CAST_TYPE(clang::ConstantArrayType, T));
356      break;
357    }
358    default: {
359      // TODO(zonr): warn that type is not exportable.
360      fprintf(stderr,
361              "RSExportType::Create : type '%s' is not exportable\n",
362              T->getTypeClassName());
363      break;
364    }
365  }
366
367  return ET;
368}
369
370RSExportType *RSExportType::Create(RSContext *Context, const clang::Type *T) {
371  llvm::StringRef TypeName;
372  if (NormalizeType(T, TypeName))
373    return Create(Context, T, TypeName);
374  else
375    return NULL;
376}
377
378RSExportType *RSExportType::CreateFromDecl(RSContext *Context,
379                                           const clang::VarDecl *VD) {
380  return RSExportType::Create(Context, GetTypeOfDecl(VD));
381}
382
383size_t RSExportType::GetTypeStoreSize(const RSExportType *ET) {
384  return ET->getRSContext()->getTargetData()->getTypeStoreSize(
385      ET->getLLVMType());
386}
387
388size_t RSExportType::GetTypeAllocSize(const RSExportType *ET) {
389  if (ET->getClass() == RSExportType::ExportClassRecord)
390    return static_cast<const RSExportRecordType*>(ET)->getAllocSize();
391  else
392    return ET->getRSContext()->getTargetData()->getTypeAllocSize(
393        ET->getLLVMType());
394}
395
396RSExportType::RSExportType(RSContext *Context,
397                           ExportClass Class,
398                           const llvm::StringRef &Name)
399    : RSExportable(Context, RSExportable::EX_TYPE),
400      mContext(Context),
401      mClass(Class),
402      // Make a copy on Name since memory stored @Name is either allocated in
403      // ASTContext or allocated in GetTypeName which will be destroyed later.
404      mName(Name.data(), Name.size()),
405      mLLVMType(NULL) {
406  // Don't cache the type whose name start with '<'. Those type failed to
407  // get their name since constructing their name in GetTypeName() requiring
408  // complicated work.
409  if (!Name.startswith(DUMMY_RS_TYPE_NAME_PREFIX))
410    // TODO(zonr): Need to check whether the insertion is successful or not.
411    Context->insertExportType(llvm::StringRef(Name), this);
412  return;
413}
414
415/************************** RSExportPrimitiveType **************************/
416llvm::ManagedStatic<RSExportPrimitiveType::RSObjectTypeMapTy>
417RSExportPrimitiveType::RSObjectTypeMap;
418
419llvm::Type *RSExportPrimitiveType::RSObjectLLVMType = NULL;
420
421bool RSExportPrimitiveType::IsPrimitiveType(const clang::Type *T) {
422  if ((T != NULL) && (T->getTypeClass() == clang::Type::Builtin))
423    return true;
424  else
425    return false;
426}
427
428RSExportPrimitiveType::DataType
429RSExportPrimitiveType::GetRSObjectType(const llvm::StringRef &TypeName) {
430  if (TypeName.empty())
431    return DataTypeUnknown;
432
433  if (RSObjectTypeMap->empty()) {
434#define USE_ELEMENT_DATA_TYPE
435#define DEF_RS_OBJECT_TYPE(type, name)                                  \
436    RSObjectTypeMap->GetOrCreateValue(name, GET_ELEMENT_DATA_TYPE(type));
437#include "slang_rs_export_element_support.inc"
438  }
439
440  RSObjectTypeMapTy::const_iterator I = RSObjectTypeMap->find(TypeName);
441  if (I == RSObjectTypeMap->end())
442    return DataTypeUnknown;
443  else
444    return I->getValue();
445}
446
447RSExportPrimitiveType::DataType
448RSExportPrimitiveType::GetRSObjectType(const clang::Type *T) {
449  T = GET_CANONICAL_TYPE(T);
450  if ((T == NULL) || (T->getTypeClass() != clang::Type::Record))
451    return DataTypeUnknown;
452
453  return GetRSObjectType( RSExportType::GetTypeName(T) );
454}
455
456const size_t
457RSExportPrimitiveType::SizeOfDataTypeInBits[
458    RSExportPrimitiveType::DataTypeMax + 1] = {
459  16,  // DataTypeFloat16
460  32,  // DataTypeFloat32
461  64,  // DataTypeFloat64
462  8,   // DataTypeSigned8
463  16,  // DataTypeSigned16
464  32,  // DataTypeSigned32
465  64,  // DataTypeSigned64
466  8,   // DataTypeUnsigned8
467  16,  // DataTypeUnsigned16
468  32,  // DataTypeUnsigned32
469  64,  // DataTypeUnSigned64
470  1,   // DataTypeBoolean
471
472  16,  // DataTypeUnsigned565
473  16,  // DataTypeUnsigned5551
474  16,  // DataTypeUnsigned4444
475
476  128,  // DataTypeRSMatrix2x2
477  288,  // DataTypeRSMatrix3x3
478  512,  // DataTypeRSMatrix4x4
479
480  32,  // DataTypeRSElement
481  32,  // DataTypeRSType
482  32,  // DataTypeRSAllocation
483  32,  // DataTypeRSSampler
484  32,  // DataTypeRSScript
485  32,  // DataTypeRSMesh
486  32,  // DataTypeRSProgramFragment
487  32,  // DataTypeRSProgramVertex
488  32,  // DataTypeRSProgramRaster
489  32,  // DataTypeRSProgramStore
490  32,  // DataTypeRSFont
491  0
492};
493
494size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
495  assert(((EPT->getType() >= DataTypeFloat32) &&
496          (EPT->getType() < DataTypeMax)) &&
497         "RSExportPrimitiveType::GetSizeInBits : unknown data type");
498  return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ];
499}
500
501RSExportPrimitiveType::DataType
502RSExportPrimitiveType::GetDataType(const clang::Type *T) {
503  if (T == NULL)
504    return DataTypeUnknown;
505
506  switch (T->getTypeClass()) {
507    case clang::Type::Builtin: {
508      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
509      switch (BT->getKind()) {
510#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type)       \
511        case builtin_type: {                                    \
512          return type;                                          \
513          break;                                                \
514        }
515#include "slang_rs_export_type_support.inc"
516
517        // The size of types Long, ULong and WChar depend on platform so we
518        // abandon the support to them. Type of its size exceeds 32 bits (e.g.
519        // int64_t, double, etc.): no support
520
521        default: {
522          // TODO(zonr): warn that the type is unsupported
523          fprintf(stderr, "RSExportPrimitiveType::GetDataType : built-in type "
524                          "has no corresponding data type for built-in type");
525          break;
526        }
527      }
528      break;
529    }
530
531    case clang::Type::Record: {
532      // must be RS object type
533      return RSExportPrimitiveType::GetRSObjectType(T);
534      break;
535    }
536
537    default: {
538      fprintf(stderr, "RSExportPrimitiveType::GetDataType : type '%s' is not "
539                      "supported primitive type", T->getTypeClassName());
540      break;
541    }
542  }
543
544  return DataTypeUnknown;
545}
546
547RSExportPrimitiveType
548*RSExportPrimitiveType::Create(RSContext *Context,
549                               const clang::Type *T,
550                               const llvm::StringRef &TypeName,
551                               DataKind DK,
552                               bool Normalized) {
553  DataType DT = GetDataType(T);
554
555  if ((DT == DataTypeUnknown) || TypeName.empty())
556    return NULL;
557  else
558    return new RSExportPrimitiveType(Context, ExportClassPrimitive, TypeName,
559                                     DT, DK, Normalized);
560}
561
562RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
563                                                     const clang::Type *T,
564                                                     DataKind DK) {
565  llvm::StringRef TypeName;
566  if (RSExportType::NormalizeType(T, TypeName) && IsPrimitiveType(T))
567    return Create(Context, T, TypeName, DK);
568  else
569    return NULL;
570}
571
572const llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
573  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
574
575  if (isRSObjectType()) {
576    // struct {
577    //   int *p;
578    // } __attribute__((packed, aligned(pointer_size)))
579    //
580    // which is
581    //
582    // <{ [1 x i32] }> in LLVM
583    //
584    if (RSObjectLLVMType == NULL) {
585      std::vector<const llvm::Type *> Elements;
586      Elements.push_back(llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1));
587      RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
588    }
589    return RSObjectLLVMType;
590  }
591
592  switch (mType) {
593    case DataTypeFloat32: {
594      return llvm::Type::getFloatTy(C);
595      break;
596    }
597    case DataTypeFloat64: {
598      return llvm::Type::getDoubleTy(C);
599      break;
600    }
601    case DataTypeBoolean: {
602      return llvm::Type::getInt1Ty(C);
603      break;
604    }
605    case DataTypeSigned8:
606    case DataTypeUnsigned8: {
607      return llvm::Type::getInt8Ty(C);
608      break;
609    }
610    case DataTypeSigned16:
611    case DataTypeUnsigned16:
612    case DataTypeUnsigned565:
613    case DataTypeUnsigned5551:
614    case DataTypeUnsigned4444: {
615      return llvm::Type::getInt16Ty(C);
616      break;
617    }
618    case DataTypeSigned32:
619    case DataTypeUnsigned32: {
620      return llvm::Type::getInt32Ty(C);
621      break;
622    }
623    case DataTypeSigned64:
624    case DataTypeUnsigned64: {
625      return llvm::Type::getInt64Ty(C);
626      break;
627    }
628    default: {
629      assert(false && "Unknown data type");
630    }
631  }
632
633  return NULL;
634}
635
636/**************************** RSExportPointerType ****************************/
637
638const clang::Type *RSExportPointerType::IntegerType = NULL;
639
640RSExportPointerType
641*RSExportPointerType::Create(RSContext *Context,
642                             const clang::PointerType *PT,
643                             const llvm::StringRef &TypeName) {
644  const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
645  const RSExportType *PointeeET;
646
647  if (PointeeType->getTypeClass() != clang::Type::Pointer) {
648    PointeeET = RSExportType::Create(Context, PointeeType);
649  } else {
650    // Double or higher dimension of pointer, export as int*
651    assert(IntegerType != NULL && "Built-in integer type is not set");
652    PointeeET = RSExportPrimitiveType::Create(Context, IntegerType);
653  }
654
655  if (PointeeET == NULL) {
656    fprintf(stderr, "Failed to create type for pointee");
657    return NULL;
658  }
659
660  return new RSExportPointerType(Context, TypeName, PointeeET);
661}
662
663const llvm::Type *RSExportPointerType::convertToLLVMType() const {
664  const llvm::Type *PointeeType = mPointeeType->getLLVMType();
665  return llvm::PointerType::getUnqual(PointeeType);
666}
667
668/***************************** RSExportVectorType *****************************/
669const char* RSExportVectorType::VectorTypeNameStore[][3] = {
670  /* 0 */ { "char2",      "char3",    "char4" },
671  /* 1 */ { "uchar2",     "uchar3",   "uchar4" },
672  /* 2 */ { "short2",     "short3",   "short4" },
673  /* 3 */ { "ushort2",    "ushort3",  "ushort4" },
674  /* 4 */ { "int2",       "int3",     "int4" },
675  /* 5 */ { "uint2",      "uint3",    "uint4" },
676  /* 6 */ { "float2",     "float3",   "float4" },
677  /* 7 */ { "double2",    "double3",  "double4" },
678  /* 8 */ { "long2",      "long3",    "long4" },
679  /* 9 */ { "ulong2",     "ulong3",   "ulong4" },
680};
681
682llvm::StringRef
683RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
684  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
685
686  if ((ElementType->getTypeClass() != clang::Type::Builtin))
687    return llvm::StringRef();
688
689  const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType,
690                                                  ElementType);
691  const char **BaseElement = NULL;
692
693  switch (BT->getKind()) {
694    // Compiler is smart enough to optimize following *big if branches* since
695    // they all become "constant comparison" after macro expansion
696#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type)       \
697    case builtin_type: {                                                \
698      if (type == RSExportPrimitiveType::DataTypeSigned8) \
699        BaseElement = VectorTypeNameStore[0];                           \
700      else if (type == RSExportPrimitiveType::DataTypeUnsigned8) \
701        BaseElement = VectorTypeNameStore[1];                           \
702      else if (type == RSExportPrimitiveType::DataTypeSigned16) \
703        BaseElement = VectorTypeNameStore[2];                           \
704      else if (type == RSExportPrimitiveType::DataTypeUnsigned16) \
705        BaseElement = VectorTypeNameStore[3];                           \
706      else if (type == RSExportPrimitiveType::DataTypeSigned32) \
707        BaseElement = VectorTypeNameStore[4];                           \
708      else if (type == RSExportPrimitiveType::DataTypeUnsigned32) \
709        BaseElement = VectorTypeNameStore[5];                           \
710      else if (type == RSExportPrimitiveType::DataTypeFloat32) \
711        BaseElement = VectorTypeNameStore[6];                           \
712      else if (type == RSExportPrimitiveType::DataTypeFloat64) \
713        BaseElement = VectorTypeNameStore[7];                           \
714      else if (type == RSExportPrimitiveType::DataTypeSigned64) \
715        BaseElement = VectorTypeNameStore[8];                           \
716      else if (type == RSExportPrimitiveType::DataTypeUnsigned64) \
717        BaseElement = VectorTypeNameStore[9];                           \
718      else if (type == RSExportPrimitiveType::DataTypeBoolean) \
719        BaseElement = VectorTypeNameStore[0];                          \
720      break;  \
721    }
722#include "slang_rs_export_type_support.inc"
723    default: {
724      return llvm::StringRef();
725    }
726  }
727
728  if ((BaseElement != NULL) &&
729      (EVT->getNumElements() > 1) &&
730      (EVT->getNumElements() <= 4))
731    return BaseElement[EVT->getNumElements() - 2];
732  else
733    return llvm::StringRef();
734}
735
736RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
737                                               const clang::ExtVectorType *EVT,
738                                               const llvm::StringRef &TypeName,
739                                               DataKind DK,
740                                               bool Normalized) {
741  assert(EVT != NULL && EVT->getTypeClass() == clang::Type::ExtVector);
742
743  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
744  RSExportPrimitiveType::DataType DT =
745      RSExportPrimitiveType::GetDataType(ElementType);
746
747  if (DT != RSExportPrimitiveType::DataTypeUnknown)
748    return new RSExportVectorType(Context,
749                                  TypeName,
750                                  DT,
751                                  DK,
752                                  Normalized,
753                                  EVT->getNumElements());
754  else
755    fprintf(stderr, "RSExportVectorType::Create : unsupported base element "
756                    "type\n");
757  return NULL;
758}
759
760const llvm::Type *RSExportVectorType::convertToLLVMType() const {
761  const llvm::Type *ElementType = RSExportPrimitiveType::convertToLLVMType();
762  return llvm::VectorType::get(ElementType, getNumElement());
763}
764
765/***************************** RSExportMatrixType *****************************/
766RSExportMatrixType *RSExportMatrixType::Create(RSContext *Context,
767                                               const clang::RecordType *RT,
768                                               const llvm::StringRef &TypeName,
769                                               unsigned Dim) {
770  assert((RT != NULL) && (RT->getTypeClass() == clang::Type::Record));
771  assert((Dim > 1) && "Invalid dimension of matrix");
772
773  // Check whether the struct rs_matrix is in our expected form (but assume it's
774  // correct if we're not sure whether it's correct or not)
775  const clang::RecordDecl* RD = RT->getDecl();
776  RD = RD->getDefinition();
777  if (RD != NULL) {
778    // Find definition, perform further examination
779    if (RD->field_empty()) {
780      fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: "
781                      "must have 1 field for saving values", TypeName.data());
782      return NULL;
783    }
784
785    clang::RecordDecl::field_iterator FIT = RD->field_begin();
786    const clang::FieldDecl *FD = *FIT;
787    const clang::Type *FT = RSExportType::GetTypeOfDecl(FD);
788    if ((FT == NULL) || (FT->getTypeClass() != clang::Type::ConstantArray)) {
789      fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: "
790                      "first field should be an array with constant size",
791              TypeName.data());
792      return NULL;
793    }
794    const clang::ConstantArrayType *CAT =
795      static_cast<const clang::ConstantArrayType *>(FT);
796    const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
797    if ((ElementType == NULL) ||
798        (ElementType->getTypeClass() != clang::Type::Builtin) ||
799        (static_cast<const clang::BuiltinType *>(ElementType)->getKind()
800          != clang::BuiltinType::Float)) {
801      fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: "
802                      "first field should be a float array", TypeName.data());
803      return NULL;
804    }
805
806    if (CAT->getSize() != Dim * Dim) {
807      fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: "
808                      "first field should be an array with size %d",
809              TypeName.data(), Dim * Dim);
810      return NULL;
811    }
812
813    FIT++;
814    if (FIT != RD->field_end()) {
815      fprintf(stderr, "RSExportMatrixType::Create : invalid %s struct: "
816                      "must have exactly 1 field", TypeName.data());
817      return NULL;
818    }
819  }
820
821  return new RSExportMatrixType(Context, TypeName, Dim);
822}
823
824const llvm::Type *RSExportMatrixType::convertToLLVMType() const {
825  // Construct LLVM type:
826  // struct {
827  //  float X[mDim * mDim];
828  // }
829
830  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
831  llvm::ArrayType *X = llvm::ArrayType::get(llvm::Type::getFloatTy(C),
832                                            mDim * mDim);
833  return llvm::StructType::get(C, X, NULL);
834}
835
836/************************* RSExportConstantArrayType *************************/
837RSExportConstantArrayType
838*RSExportConstantArrayType::Create(RSContext *Context,
839                                   const clang::ConstantArrayType *CAT) {
840  assert(CAT != NULL && CAT->getTypeClass() == clang::Type::ConstantArray);
841
842  assert((CAT->getSize().getActiveBits() < 32) && "array too large");
843
844  unsigned Size = static_cast<unsigned>(CAT->getSize().getZExtValue());
845  assert((Size > 0) && "Constant array should have size greater than 0");
846
847  const clang::Type *ElementType = GET_CONSTANT_ARRAY_ELEMENT_TYPE(CAT);
848  RSExportType *ElementET = RSExportType::Create(Context, ElementType);
849
850  if (ElementET == NULL) {
851    fprintf(stderr, "RSExportConstantArrayType::Create : failed to create "
852                    "RSExportType for array element.\n");
853    return NULL;
854  }
855
856  return new RSExportConstantArrayType(Context,
857                                       ElementET,
858                                       Size);
859}
860
861const llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
862  return llvm::ArrayType::get(mElementType->getLLVMType(), getSize());
863}
864
865/**************************** RSExportRecordType ****************************/
866RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
867                                               const clang::RecordType *RT,
868                                               const llvm::StringRef &TypeName,
869                                               bool mIsArtificial) {
870  assert(RT != NULL && RT->getTypeClass() == clang::Type::Record);
871
872  const clang::RecordDecl *RD = RT->getDecl();
873  assert(RD->isStruct());
874
875  RD = RD->getDefinition();
876  if (RD == NULL) {
877    // TODO(zonr): warn that actual struct definition isn't declared in this
878    //             moudle.
879    fprintf(stderr, "RSExportRecordType::Create : this struct is not defined "
880                    "in this module.");
881    return NULL;
882  }
883
884  // Struct layout construct by clang. We rely on this for obtaining the
885  // alloc size of a struct and offset of every field in that struct.
886  const clang::ASTRecordLayout *RL =
887      &Context->getASTContext()->getASTRecordLayout(RD);
888  assert((RL != NULL) && "Failed to retrieve the struct layout from Clang.");
889
890  RSExportRecordType *ERT =
891      new RSExportRecordType(Context,
892                             TypeName,
893                             RD->hasAttr<clang::PackedAttr>(),
894                             mIsArtificial,
895                             (RL->getSize() >> 3));
896  unsigned int Index = 0;
897
898  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
899           FE = RD->field_end();
900       FI != FE;
901       FI++, Index++) {
902#define FAILED_CREATE_FIELD(err)    do {         \
903      if (*err)                                                          \
904        fprintf(stderr, \
905                "RSExportRecordType::Create : failed to create field (%s)\n", \
906                err);                                                   \
907      delete ERT;                                                       \
908      return NULL;                                                      \
909    } while (false)
910
911    // FIXME: All fields should be primitive type
912    assert((*FI)->getKind() == clang::Decl::Field);
913    clang::FieldDecl *FD = *FI;
914
915    // We don't support bit field
916    //
917    // TODO(zonr): allow bitfield with size 8, 16, 32
918    if (FD->isBitField())
919      FAILED_CREATE_FIELD("bit field is not supported");
920
921    // Type
922    RSExportType *ET = RSExportElement::CreateFromDecl(Context, FD);
923
924    if (ET != NULL)
925      ERT->mFields.push_back(
926          new Field(ET, FD->getName(), ERT,
927                    static_cast<size_t>(RL->getFieldOffset(Index) >> 3)));
928    else
929      FAILED_CREATE_FIELD(FD->getName().str().c_str());
930#undef FAILED_CREATE_FIELD
931  }
932
933  return ERT;
934}
935
936const llvm::Type *RSExportRecordType::convertToLLVMType() const {
937  std::vector<const llvm::Type*> FieldTypes;
938
939  for (const_field_iterator FI = fields_begin(),
940           FE = fields_end();
941       FI != FE;
942       FI++) {
943    const Field *F = *FI;
944    const RSExportType *FET = F->getType();
945
946    FieldTypes.push_back(FET->getLLVMType());
947  }
948
949  return llvm::StructType::get(getRSContext()->getLLVMContext(),
950                               FieldTypes,
951                               mIsPacked);
952}
953