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