slang_rs_export_type.cpp revision 91a3783ce1f4eb9ad6e9c1ecdbd27f3d6dc58634
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::DataTypeBoolean)      \
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  16, // DataTypeFloat16
440  32, // DataTypeFloat32
441  64, // DataTypeFloat64
442  8,  // DataTypeSigned8
443  16, // DataTypeSigned16
444  32, // DataTypeSigned32
445  64, // DataTypeSigned64
446  8,  // DataTypeUnsigned8
447  16, // DataTypeUnsigned16
448  32, // DataTypeUnsigned32
449  64, // DataTypeUnSigned64
450  1,  // DataTypeBoolean
451
452  16, // DataTypeUnsigned565
453  16, // DataTypeUnsigned5551
454  16, // DataTypeUnsigned4444
455
456  128, // DataTypeRSMatrix2x2
457  288, // DataTypeRSMatrix3x3
458  512, // DataTypeRSMatrix4x4
459
460  32, // DataTypeRSElement
461  32, // DataTypeRSType
462  32, // DataTypeRSAllocation
463  32, // DataTypeRSSampler
464  32, // DataTypeRSScript
465  32, // DataTypeRSMesh
466  32, // DataTypeRSProgramFragment
467  32, // DataTypeRSProgramVertex
468  32, // DataTypeRSProgramRaster
469  32, // DataTypeRSProgramStore
470  32, // DataTypeRSFont
471  0
472};
473
474size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType *EPT) {
475  assert(((EPT->getType() >= DataTypeFloat32) &&
476          (EPT->getType() < DataTypeMax)) &&
477         "RSExportPrimitiveType::GetSizeInBits : unknown data type");
478  return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ];
479}
480
481RSExportPrimitiveType::DataType
482RSExportPrimitiveType::GetDataType(const clang::Type* T) {
483  if (T == NULL)
484    return DataTypeUnknown;
485
486  switch (T->getTypeClass()) {
487    case clang::Type::Builtin: {
488      const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType, T);
489      switch (BT->getKind()) {
490#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type)       \
491        case builtin_type: {                                    \
492          return type;                                          \
493          break;                                                \
494        }
495#include "slang_rs_export_type_support.inc"
496
497        // The size of types Long, ULong and WChar depend on platform so we
498        // abandon the support to them. Type of its size exceeds 32 bits (e.g.
499        // int64_t, double, etc.): no support
500
501        default: {
502          // TODO: warning the user: unsupported type
503          fprintf(stderr, "RSExportPrimitiveType::GetDataType : built-in type "
504                          "has no corresponding data type for built-in type");
505          break;
506        }
507      }
508      break;
509    }
510
511    case clang::Type::Record: {
512      // must be RS object type
513      return RSExportPrimitiveType::GetRSObjectType(T);
514      break;
515    }
516
517    default: {
518      fprintf(stderr, "RSExportPrimitiveType::GetDataType : type '%s' is not "
519                      "supported primitive type", T->getTypeClassName());
520      break;
521    }
522  }
523
524  return DataTypeUnknown;
525}
526
527RSExportPrimitiveType
528*RSExportPrimitiveType::Create(RSContext *Context,
529                               const clang::Type *T,
530                               const llvm::StringRef &TypeName,
531                               DataKind DK,
532                               bool Normalized) {
533  DataType DT = GetDataType(T);
534
535  if ((DT == DataTypeUnknown) || TypeName.empty())
536    return NULL;
537  else
538    return new RSExportPrimitiveType(Context, TypeName, DT, DK, Normalized);
539}
540
541RSExportPrimitiveType *RSExportPrimitiveType::Create(RSContext *Context,
542                                                     const clang::Type *T,
543                                                     DataKind DK) {
544  llvm::StringRef TypeName;
545  if (RSExportType::NormalizeType(T, TypeName) && IsPrimitiveType(T))
546    return Create(Context, T, TypeName, DK);
547  else
548    return NULL;
549}
550
551RSExportType::ExportClass RSExportPrimitiveType::getClass() const {
552  return RSExportType::ExportClassPrimitive;
553}
554
555const llvm::Type *RSExportPrimitiveType::convertToLLVMType() const {
556  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
557
558  if (isRSObjectType()) {
559    // struct {
560    //   int *p;
561    // } __attribute__((packed, aligned(pointer_size)))
562    //
563    // which is
564    //
565    // <{ [1 x i32] }> in LLVM
566    //
567    if (RSObjectLLVMType == NULL) {
568      std::vector<const llvm::Type *> Elements;
569      Elements.push_back( llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1) );
570      RSObjectLLVMType = llvm::StructType::get(C, Elements, true);
571    }
572    return RSObjectLLVMType;
573  }
574
575  switch (mType) {
576    case DataTypeFloat32: {
577      return llvm::Type::getFloatTy(C);
578      break;
579    }
580    case DataTypeFloat64: {
581      return llvm::Type::getDoubleTy(C);
582      break;
583    }
584    case DataTypeBoolean: {
585      return llvm::Type::getInt1Ty(C);
586      break;
587    }
588    case DataTypeSigned8:
589    case DataTypeUnsigned8: {
590      return llvm::Type::getInt8Ty(C);
591      break;
592    }
593    case DataTypeSigned16:
594    case DataTypeUnsigned16:
595    case DataTypeUnsigned565:
596    case DataTypeUnsigned5551:
597    case DataTypeUnsigned4444: {
598      return llvm::Type::getInt16Ty(C);
599      break;
600    }
601    case DataTypeSigned32:
602    case DataTypeUnsigned32: {
603      return llvm::Type::getInt32Ty(C);
604      break;
605    }
606    case DataTypeSigned64: {
607    // case DataTypeUnsigned64:
608      return llvm::Type::getInt64Ty(C);
609      break;
610    }
611    default: {
612      assert(false && "Unknown data type");
613    }
614  }
615
616  return NULL;
617}
618
619/**************************** RSExportPointerType ****************************/
620
621const clang::Type *RSExportPointerType::IntegerType = NULL;
622
623RSExportPointerType
624*RSExportPointerType::Create(RSContext *Context,
625                             const clang::PointerType *PT,
626                             const llvm::StringRef &TypeName) {
627  const clang::Type *PointeeType = GET_POINTEE_TYPE(PT);
628  const RSExportType *PointeeET;
629
630  if (PointeeType->getTypeClass() != clang::Type::Pointer) {
631    PointeeET = RSExportType::Create(Context, PointeeType);
632  } else {
633    // Double or higher dimension of pointer, export as int*
634    assert(IntegerType != NULL && "Built-in integer type is not set");
635    PointeeET = RSExportPrimitiveType::Create(Context, IntegerType);
636  }
637
638  if (PointeeET == NULL) {
639    fprintf(stderr, "Failed to create type for pointee");
640    return NULL;
641  }
642
643  return new RSExportPointerType(Context, TypeName, PointeeET);
644}
645
646RSExportType::ExportClass RSExportPointerType::getClass() const {
647  return RSExportType::ExportClassPointer;
648}
649
650const llvm::Type *RSExportPointerType::convertToLLVMType() const {
651  const llvm::Type *PointeeType = mPointeeType->getLLVMType();
652  return llvm::PointerType::getUnqual(PointeeType);
653}
654
655/************************* RSExportConstantArrayType *************************/
656llvm::StringRef
657RSExportConstantArrayType::GetTypeName(const clang::ConstantArrayType *CT) {
658  llvm::APInt i = CT->getSize();
659  if (i == 4) {
660    return llvm::StringRef("rs_matrix2x2");
661  } else if (i == 9) {
662    return llvm::StringRef("rs_matrix3x3");
663  } else if (i == 16) {
664    return llvm::StringRef("rs_matrix4x4");
665  }
666  return llvm::StringRef();
667}
668
669RSExportConstantArrayType
670*RSExportConstantArrayType::Create(RSContext *Context,
671                                   const clang::ConstantArrayType *CT,
672                                   const llvm::StringRef &TypeName,
673                                   DataKind DK,
674                                   bool Normalized) {
675  assert(CT != NULL && CT->getTypeClass() == clang::Type::ConstantArray);
676
677  int64_t Size = CT->getSize().getSExtValue();
678  RSExportPrimitiveType::DataType DT;
679  if (Size == 4) {
680    DT = RSExportPrimitiveType::DataTypeRSMatrix2x2;
681  } else if (Size == 9) {
682    DT = RSExportPrimitiveType::DataTypeRSMatrix3x3;
683  } else if (Size == 16) {
684    DT = RSExportPrimitiveType::DataTypeRSMatrix4x4;
685  } else {
686    fprintf(stderr, "RSExportConstantArrayType::Create : unsupported base "
687                    "element type\n");
688    return NULL;
689  }
690
691  return new RSExportConstantArrayType(Context,
692                                       TypeName,
693                                       DT,
694                                       DK,
695                                       Normalized,
696                                       Size);
697}
698
699RSExportType::ExportClass RSExportConstantArrayType::getClass() const {
700  return RSExportType::ExportClassConstantArray;
701}
702
703const llvm::Type *RSExportConstantArrayType::convertToLLVMType() const {
704  llvm::LLVMContext &C = getRSContext()->getLLVMContext();
705  const llvm::Type *typ;
706  switch (getType()) {
707    case DataTypeFloat32:
708    case DataTypeRSMatrix2x2:
709    case DataTypeRSMatrix3x3:
710    case DataTypeRSMatrix4x4: {
711      typ = llvm::Type::getFloatTy(C);
712      break;
713    }
714    case DataTypeFloat64: {
715      typ = llvm::Type::getDoubleTy(C);
716      break;
717    }
718    case DataTypeBoolean: {
719      typ = llvm::Type::getInt1Ty(C);
720      break;
721    }
722    case DataTypeSigned8:
723    case DataTypeUnsigned8: {
724      typ = llvm::Type::getInt8Ty(C);
725      break;
726    }
727    case DataTypeSigned16:
728    case DataTypeUnsigned16:
729    case DataTypeUnsigned565:
730    case DataTypeUnsigned5551:
731    case DataTypeUnsigned4444: {
732      typ = llvm::Type::getInt16Ty(C);
733      break;
734    }
735    case DataTypeSigned32:
736    case DataTypeUnsigned32: {
737      typ = llvm::Type::getInt32Ty(C);
738      break;
739    }
740    case DataTypeSigned64: {
741    //case DataTypeUnsigned64:
742      typ = llvm::Type::getInt64Ty(C);
743      break;
744    }
745    default: {
746      assert(false && "Unknown data type");
747      break;
748    }
749  }
750  return llvm::ArrayType::get(typ, mNumElement);
751}
752
753/****************************** RSExportVectorType ******************************/
754const char* RSExportVectorType::VectorTypeNameStore[][3] = {
755  /* 0 */ { "char2",      "char3",    "char4" },
756  /* 1 */ { "uchar2",     "uchar3",   "uchar4" },
757  /* 2 */ { "short2",     "short3",   "short4" },
758  /* 3 */ { "ushort2",    "ushort3",  "ushort4" },
759  /* 4 */ { "int2",       "int3",     "int4" },
760  /* 5 */ { "uint2",      "uint3",    "uint4" },
761  /* 6 */ { "float2",     "float3",   "float4" },
762  /* 7 */ { "double2",    "double3",  "double4" },
763  /* 8 */ { "long2",      "long3",    "long4" },
764};
765
766llvm::StringRef RSExportVectorType::GetTypeName(const clang::ExtVectorType *EVT) {
767  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
768
769  if ((ElementType->getTypeClass() != clang::Type::Builtin))
770    return llvm::StringRef();
771
772  const clang::BuiltinType *BT = UNSAFE_CAST_TYPE(clang::BuiltinType,
773                                                  ElementType);
774  const char **BaseElement = NULL;
775
776  switch (BT->getKind()) {
777    // Compiler is smart enough to optimize following *big if branches* since
778    // they all become "constant comparison" after macro expansion
779#define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type)       \
780    case builtin_type: {                                                \
781      if (type == RSExportPrimitiveType::DataTypeSigned8) \
782        BaseElement = VectorTypeNameStore[0];                           \
783      else if (type == RSExportPrimitiveType::DataTypeUnsigned8) \
784        BaseElement = VectorTypeNameStore[1];                           \
785      else if (type == RSExportPrimitiveType::DataTypeSigned16) \
786        BaseElement = VectorTypeNameStore[2];                           \
787      else if (type == RSExportPrimitiveType::DataTypeUnsigned16) \
788        BaseElement = VectorTypeNameStore[3];                           \
789      else if (type == RSExportPrimitiveType::DataTypeSigned32) \
790        BaseElement = VectorTypeNameStore[4];                           \
791      else if (type == RSExportPrimitiveType::DataTypeUnsigned32) \
792        BaseElement = VectorTypeNameStore[5];                           \
793      else if (type == RSExportPrimitiveType::DataTypeFloat32) \
794        BaseElement = VectorTypeNameStore[6];                           \
795      else if (type == RSExportPrimitiveType::DataTypeFloat64) \
796        BaseElement = VectorTypeNameStore[7];                           \
797      else if (type == RSExportPrimitiveType::DataTypeSigned64) \
798        BaseElement = VectorTypeNameStore[8];                           \
799      else if (type == RSExportPrimitiveType::DataTypeBoolean) \
800        BaseElement = VectorTypeNameStore[0];                          \
801      break;  \
802    }
803#include "slang_rs_export_type_support.inc"
804    default: {
805      return llvm::StringRef();
806    }
807  }
808
809  if ((BaseElement != NULL) &&
810      (EVT->getNumElements() > 1) &&
811      (EVT->getNumElements() <= 4))
812    return BaseElement[EVT->getNumElements() - 2];
813  else
814    return llvm::StringRef();
815}
816
817RSExportVectorType *RSExportVectorType::Create(RSContext *Context,
818                                               const clang::ExtVectorType *EVT,
819                                               const llvm::StringRef &TypeName,
820                                               DataKind DK,
821                                               bool Normalized) {
822  assert(EVT != NULL && EVT->getTypeClass() == Type::ExtVector);
823
824  const clang::Type *ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT);
825  RSExportPrimitiveType::DataType DT =
826      RSExportPrimitiveType::GetDataType(ElementType);
827
828  if (DT != RSExportPrimitiveType::DataTypeUnknown)
829    return new RSExportVectorType(Context,
830                                  TypeName,
831                                  DT,
832                                  DK,
833                                  Normalized,
834                                  EVT->getNumElements());
835  else
836    fprintf(stderr, "RSExportVectorType::Create : unsupported base element "
837                    "type\n");
838  return NULL;
839}
840
841RSExportType::ExportClass RSExportVectorType::getClass() const {
842  return RSExportType::ExportClassVector;
843}
844
845const llvm::Type* RSExportVectorType::convertToLLVMType() const {
846  const llvm::Type* ElementType = RSExportPrimitiveType::convertToLLVMType();
847  return llvm::VectorType::get(ElementType, getNumElement());
848}
849
850/**************************** RSExportRecordType ****************************/
851RSExportRecordType *RSExportRecordType::Create(RSContext *Context,
852                                               const clang::RecordType *RT,
853                                               const llvm::StringRef &TypeName,
854                                               bool mIsArtificial) {
855  assert(RT != NULL && RT->getTypeClass() == Type::Record);
856
857  const clang::RecordDecl *RD = RT->getDecl();
858  assert(RD->isStruct());
859
860  RD = RD->getDefinition();
861  if (RD == NULL) {
862    // TODO: warning: actual struct definition isn't declared in this moudle
863    fprintf(stderr, "RSExportRecordType::Create : this struct is not defined "
864                    "in this module.");
865    return NULL;
866  }
867
868  RSExportRecordType *ERT = new RSExportRecordType(Context,
869                                                   TypeName,
870                                                   RD->
871                                                   hasAttr<clang::PackedAttr>(),
872                                                   mIsArtificial);
873  unsigned int Index = 0;
874
875  for (clang::RecordDecl::field_iterator FI = RD->field_begin(),
876           FE = RD->field_end();
877       FI != FE;
878       FI++, Index++) {
879#define FAILED_CREATE_FIELD(err)    do {         \
880      if (*err)                                                          \
881        fprintf(stderr, \
882                "RSExportRecordType::Create : failed to create field (%s)\n", \
883                err);                                                   \
884      delete ERT;                                                       \
885      return NULL;                                                      \
886    } while (false)
887
888    // FIXME: All fields should be primitive type
889    assert((*FI)->getKind() == clang::Decl::Field);
890    clang::FieldDecl *FD = *FI;
891
892    // We don't support bit field
893    //
894    // TODO: allow bitfield with size 8, 16, 32
895    if (FD->isBitField())
896      FAILED_CREATE_FIELD("bit field is not supported");
897
898    // Type
899    RSExportType* ET = RSExportElement::CreateFromDecl(Context, FD);
900
901    if(ET != NULL)
902      ERT->mFields.push_back( new Field(ET, FD->getName(), ERT, Index) );
903    else
904      FAILED_CREATE_FIELD(FD->getName().str().c_str());
905#undef FAILED_CREATE_FIELD
906  }
907
908  const clang::ASTRecordLayout &ASTRL =
909      Context->getASTContext()->getASTRecordLayout(RD);
910  ERT->AllocSize =
911      (ASTRL.getSize() > ASTRL.getDataSize()) ?
912      (ASTRL.getSize() >> 3) :
913      (ASTRL.getDataSize() >> 3);
914
915  return ERT;
916}
917
918RSExportType::ExportClass RSExportRecordType::getClass() const {
919  return RSExportType::ExportClassRecord;
920}
921
922const llvm::Type* RSExportRecordType::convertToLLVMType() const {
923  std::vector<const llvm::Type*> FieldTypes;
924
925  for (const_field_iterator FI = fields_begin(),
926           FE = fields_end();
927       FI != FE;
928       FI++) {
929    const Field *F = *FI;
930    const RSExportType *FET = F->getType();
931
932    FieldTypes.push_back(FET->getLLVMType());
933  }
934
935  return llvm::StructType::get(getRSContext()->getLLVMContext(),
936                               FieldTypes,
937                               mIsPacked);
938}
939
940/************************* RSExportRecordType::Field *************************/
941size_t RSExportRecordType::Field::getOffsetInParent() const {
942  // Struct layout obtains below will be cached by LLVM
943  const llvm::StructLayout *SL =
944      mParent->getRSContext()->getTargetData()->getStructLayout(
945          static_cast<const llvm::StructType*>(mParent->getLLVMType())
946                                                                );
947  return SL->getElementOffset(mIndex);
948}
949