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