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