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