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