| #include <vector> |
| |
| #include "slang_rs_context.hpp" |
| #include "slang_rs_export_type.hpp" |
| #include "slang_rs_export_element.hpp" |
| |
| #include "llvm/Type.h" |
| #include "llvm/DerivedTypes.h" |
| |
| #include "llvm/ADT/StringExtras.h" /* for function llvm::utostr_32() */ |
| #include "llvm/Target/TargetData.h" /* for class llvm::TargetData and class llvm::StructLayout */ |
| |
| namespace slang { |
| |
| /****************************** RSExportType ******************************/ |
| bool RSExportType::NormalizeType(const Type*& T, llvm::StringRef& TypeName) { |
| llvm::SmallPtrSet<const Type*, 8> SPS = llvm::SmallPtrSet<const Type*, 8>(); |
| |
| if((T = RSExportType::TypeExportable(T, SPS)) == NULL) |
| /* TODO: warning the user: type not exportable */ |
| return false; |
| |
| /* Get type name */ |
| TypeName = RSExportType::GetTypeName(T); |
| if(TypeName.empty()) |
| /* TODO: warning the user: the type is unnmaed */ |
| return false; |
| |
| return true; |
| } |
| |
| const Type* RSExportType::GetTypeOfDecl(const DeclaratorDecl* DD) { |
| if(DD && DD->getTypeSourceInfo()) { |
| QualType T = DD->getTypeSourceInfo()->getType(); |
| if(T.isNull()) |
| return NULL; |
| else |
| return T.getTypePtr(); |
| } |
| } |
| |
| llvm::StringRef RSExportType::GetTypeName(const Type* T) { |
| T = GET_CANONICAL_TYPE(T); |
| if(T == NULL) |
| return llvm::StringRef(); |
| |
| switch(T->getTypeClass()) { |
| case Type::Builtin: |
| { |
| const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, T); |
| |
| switch(BT->getKind()) { |
| #define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ |
| case builtin_type: \ |
| /* Compiler is smart enough to optimize following *big if branches* since they all become "constant comparison" after macro expansion */ \ |
| if(type == RSExportPrimitiveType::DataTypeFloat32) return "float"; \ |
| else if(type == RSExportPrimitiveType::DataTypeUnsigned8) return "uchar"; \ |
| else if(type == RSExportPrimitiveType::DataTypeUnsigned16) return "ushort"; \ |
| else if(type == RSExportPrimitiveType::DataTypeUnsigned32) return "uint"; \ |
| else if(type == RSExportPrimitiveType::DataTypeSigned8) return "char"; \ |
| else if(type == RSExportPrimitiveType::DataTypeSigned16) return "short"; \ |
| else if(type == RSExportPrimitiveType::DataTypeSigned32) return "int"; \ |
| else if(type == RSExportPrimitiveType::DataTypeBool) return "bool"; \ |
| else assert(false && "Unknow data type of supported builtin"); \ |
| break; |
| #include "slang_rs_export_type_support.inc" |
| |
| default: assert(false && "Unknow data type of the builtin"); break; |
| } |
| } |
| break; |
| |
| case Type::Record: |
| { |
| const RecordDecl* RD = T->getAsStructureType()->getDecl(); |
| llvm::StringRef Name = RD->getName(); |
| if(Name.empty()) { |
| if(RD->getTypedefForAnonDecl() != NULL) |
| Name = RD->getTypedefForAnonDecl()->getName(); |
| |
| if(Name.empty()) |
| /* Try to find a name from redeclaration (i.e. typedef) */ |
| for(TagDecl::redecl_iterator RI = RD->redecls_begin(); |
| RI != RD->redecls_end(); |
| RI++) |
| { |
| assert(*RI != NULL && "cannot be NULL object"); |
| |
| Name = (*RI)->getName(); |
| if(!Name.empty()) |
| break; |
| } |
| } |
| return Name; |
| } |
| break; |
| |
| case Type::Pointer: |
| { |
| /* "*" plus pointee name */ |
| const Type* PT = GET_POINTEE_TYPE(T); |
| llvm::StringRef PointeeName; |
| if(NormalizeType(PT, PointeeName)) { |
| char* Name = new char[ 1 /* * */ + PointeeName.size() ]; |
| Name[0] = '*'; |
| memcpy(Name + 1, PointeeName.data(), PointeeName.size()); |
| return Name; |
| } |
| } |
| break; |
| |
| case Type::ExtVector: |
| { |
| const ExtVectorType* EVT = UNSAFE_CAST_TYPE(ExtVectorType, T); |
| return RSExportVectorType::GetTypeName(EVT); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| return llvm::StringRef(); |
| } |
| |
| const Type* RSExportType::TypeExportable(const Type* T, llvm::SmallPtrSet<const Type*, 8>& SPS) { |
| /* Normailize first */ |
| if((T = GET_CANONICAL_TYPE(T)) == NULL) |
| return NULL; |
| |
| if(SPS.count(T)) |
| return T; |
| |
| switch(T->getTypeClass()) { |
| case Type::Builtin: |
| { |
| const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, T); |
| |
| switch(BT->getKind()) { |
| #define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ |
| case builtin_type: |
| #include "slang_rs_export_type_support.inc" |
| return T; |
| break; |
| |
| default: |
| return NULL; |
| break; |
| } |
| } |
| break; |
| |
| case Type::Record: |
| { |
| if(RSExportPrimitiveType::GetRSObjectType(T) != RSExportPrimitiveType::DataTypeUnknown) |
| return T; /* RS object type, no further checks are needed */ |
| |
| /* Check internal struct */ |
| const RecordDecl* RD = T->getAsStructureType()->getDecl(); |
| if(RD != NULL) |
| RD = RD->getDefinition(); |
| |
| /* Fast check */ |
| if(RD->hasFlexibleArrayMember() || RD->hasObjectMember()) |
| return NULL; |
| |
| /* Insert myself into checking set */ |
| SPS.insert(T); |
| |
| /* Check all element */ |
| for(RecordDecl::field_iterator F = RD->field_begin(); |
| F != RD->field_end(); |
| F++) |
| { |
| const Type* FT = GetTypeOfDecl(*F); |
| FT = GET_CANONICAL_TYPE(FT); |
| |
| if(!TypeExportable(FT, SPS)) |
| /* TODO: warning: unsupported field type */ |
| return NULL; |
| } |
| |
| return T; |
| } |
| break; |
| |
| case Type::Pointer: |
| { |
| const PointerType* PT = UNSAFE_CAST_TYPE(PointerType, T); |
| const Type* PointeeType = GET_POINTEE_TYPE(PT); |
| |
| if((PointeeType->getTypeClass() != Type::Pointer) && (TypeExportable(PointeeType, SPS) == NULL) ) |
| return NULL; |
| return T; |
| } |
| break; |
| |
| case Type::ExtVector: |
| { |
| const ExtVectorType* EVT = UNSAFE_CAST_TYPE(ExtVectorType, T); |
| /* Check element numbers */ |
| if(EVT->getNumElements() < 2 || EVT->getNumElements() > 4) /* only support vector with size 2, 3 and 4 */ |
| return NULL; |
| |
| /* Check base element type */ |
| const Type* ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); |
| |
| if((ElementType->getTypeClass() != Type::Builtin) || (TypeExportable(ElementType, SPS) == NULL)) |
| return NULL; |
| return T; |
| } |
| break; |
| |
| default: |
| return NULL; |
| break; |
| } |
| } |
| |
| RSExportType* RSExportType::Create(RSContext* Context, const Type* T, const llvm::StringRef& TypeName) { |
| /* |
| * Lookup the context to see whether the type was processed before. |
| * Newly create RSExportType will insert into context in RSExportType::RSExportType() |
| */ |
| RSContext::export_type_iterator ETI = Context->findExportType(TypeName); |
| |
| if(ETI != Context->export_types_end()) |
| return ETI->second; |
| |
| RSExportType* ET = NULL; |
| switch(T->getTypeClass()) { |
| case Type::Record: |
| if(RSExportPrimitiveType::GetRSObjectType(TypeName) != RSExportPrimitiveType::DataTypeUnknown) |
| ET = RSExportPrimitiveType::Create(Context, T, TypeName); |
| else |
| ET = RSExportRecordType::Create(Context, T->getAsStructureType(), TypeName); |
| break; |
| |
| case Type::Builtin: |
| ET = RSExportPrimitiveType::Create(Context, T, TypeName); |
| break; |
| |
| case Type::Pointer: |
| ET = RSExportPointerType::Create(Context, UNSAFE_CAST_TYPE(PointerType, T), TypeName); |
| /* free the name (allocated in RSExportType::GetTypeName) */ |
| delete [] TypeName.data(); |
| break; |
| |
| case Type::ExtVector: |
| ET = RSExportVectorType::Create(Context, UNSAFE_CAST_TYPE(ExtVectorType, T), TypeName); |
| break; |
| |
| default: |
| /* TODO: warning: type is not exportable */ |
| printf("RSExportType::Create : type '%s' is not exportable\n", T->getTypeClassName()); |
| break; |
| } |
| |
| return ET; |
| } |
| |
| RSExportType* RSExportType::Create(RSContext* Context, const Type* T) { |
| llvm::StringRef TypeName; |
| if(NormalizeType(T, TypeName)) |
| return Create(Context, T, TypeName); |
| else |
| return NULL; |
| } |
| |
| RSExportType* RSExportType::CreateFromDecl(RSContext* Context, const VarDecl* VD) { |
| return RSExportType::Create(Context, GetTypeOfDecl(VD)); |
| } |
| |
| size_t RSExportType::GetTypeStoreSize(const RSExportType* ET) { |
| return ET->getRSContext()->getTargetData()->getTypeStoreSize(ET->getLLVMType()); |
| } |
| |
| size_t RSExportType::GetTypeAllocSize(const RSExportType* ET) { |
| return ET->getRSContext()->getTargetData()->getTypeAllocSize(ET->getLLVMType()); |
| } |
| |
| RSExportType::RSExportType(RSContext* Context, const llvm::StringRef& Name) : |
| mContext(Context), |
| mName(Name.data(), Name.size()), /* make a copy on Name since data of @Name which is stored in ASTContext will be destroyed later */ |
| mLLVMType(NULL) |
| { |
| /* TODO: need to check whether the insertion is successful or not */ |
| Context->insertExportType(Name, this); |
| return; |
| } |
| |
| /****************************** RSExportPrimitiveType ******************************/ |
| RSExportPrimitiveType::RSObjectTypeMapTy* RSExportPrimitiveType::RSObjectTypeMap = NULL; |
| llvm::Type* RSExportPrimitiveType::RSObjectLLVMType = NULL; |
| |
| bool RSExportPrimitiveType::IsPrimitiveType(const Type* T) { |
| if((T != NULL) && (T->getTypeClass() == Type::Builtin)) |
| return true; |
| else |
| return false; |
| } |
| |
| RSExportPrimitiveType::DataType RSExportPrimitiveType::GetRSObjectType(const llvm::StringRef& TypeName) { |
| if(TypeName.empty()) |
| return DataTypeUnknown; |
| |
| if(RSObjectTypeMap == NULL) { |
| RSObjectTypeMap = new RSObjectTypeMapTy(16); |
| |
| #define USE_ELEMENT_DATA_TYPE |
| #define DEF_RS_OBJECT_TYPE(type, name) \ |
| RSObjectTypeMap->GetOrCreateValue(name, GET_ELEMENT_DATA_TYPE(type)); |
| #include "slang_rs_export_element_support.inc" |
| } |
| |
| RSObjectTypeMapTy::const_iterator I = RSObjectTypeMap->find(TypeName); |
| if(I == RSObjectTypeMap->end()) |
| return DataTypeUnknown; |
| else |
| return I->getValue(); |
| } |
| |
| RSExportPrimitiveType::DataType RSExportPrimitiveType::GetRSObjectType(const Type* T) { |
| T = GET_CANONICAL_TYPE(T); |
| if((T == NULL) || (T->getTypeClass() != Type::Record)) |
| return DataTypeUnknown; |
| |
| return GetRSObjectType( RSExportType::GetTypeName(T) ); |
| } |
| |
| const size_t RSExportPrimitiveType::SizeOfDataTypeInBits[RSExportPrimitiveType::DataTypeMax + 1] = { |
| 0, |
| 16, /* DataTypeFloat16 */ |
| 32, /* DataTypeFloat32 */ |
| 64, /* DataTypeFloat64 */ |
| 8, /* DataTypeSigned8 */ |
| 16, /* DataTypeSigned16 */ |
| 32, /* DataTypeSigned32 */ |
| 64, /* DataTypeSigned64 */ |
| 8, /* DataTypeUnsigned8 */ |
| 16, /* DataTypeUnsigned16 */ |
| 32, /* DataTypeUnsigned32 */ |
| 64, /* DataTypeUnSigned64 */ |
| |
| 16, /* DataTypeUnsigned565 */ |
| 16, /* DataTypeUnsigned5551 */ |
| 16, /* DataTypeUnsigned4444 */ |
| |
| 1, /* DataTypeBool */ |
| |
| 32, /* DataTypeRSElement */ |
| 32, /* DataTypeRSType */ |
| 32, /* DataTypeRSAllocation */ |
| 32, /* DataTypeRSSampler */ |
| 32, /* DataTypeRSScript */ |
| 32, /* DataTypeRSMesh */ |
| 32, /* DataTypeRSProgramFragment */ |
| 32, /* DataTypeRSProgramVertex */ |
| 32, /* DataTypeRSProgramRaster */ |
| 32, /* DataTypeRSProgramStore */ |
| 32, /* DataTypeRSFont */ |
| 0 |
| }; |
| |
| size_t RSExportPrimitiveType::GetSizeInBits(const RSExportPrimitiveType* EPT) { |
| assert(((EPT->getType() >= DataTypeFloat32) && (EPT->getType() < DataTypeMax)) && "RSExportPrimitiveType::GetSizeInBits : unknown data type"); |
| return SizeOfDataTypeInBits[ static_cast<int>(EPT->getType()) ]; |
| } |
| |
| RSExportPrimitiveType::DataType RSExportPrimitiveType::GetDataType(const Type* T) { |
| if(T == NULL) |
| return DataTypeUnknown; |
| |
| switch(T->getTypeClass()) { |
| case Type::Builtin: |
| { |
| const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, T); |
| switch(BT->getKind()) { |
| #define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ |
| case builtin_type: \ |
| return type; \ |
| break; |
| #include "slang_rs_export_type_support.inc" |
| |
| /* The size of types Long, ULong and WChar depend on platform so we abandon the support to them */ |
| /* Type of its size exceeds 32 bits (e.g. int64_t, double, etc.) does not support */ |
| |
| default: |
| /* TODO: warning the user: unsupported type */ |
| printf("RSExportPrimitiveType::GetDataType : built-in type has no corresponding data type for built-in type"); |
| break; |
| } |
| } |
| break; |
| |
| case Type::Record: |
| /* must be RS object type */ |
| return RSExportPrimitiveType::GetRSObjectType(T); |
| break; |
| |
| default: |
| printf("RSExportPrimitiveType::GetDataType : type '%s' is not supported primitive type", T->getTypeClassName()); |
| break; |
| } |
| |
| return DataTypeUnknown; |
| } |
| |
| RSExportPrimitiveType* RSExportPrimitiveType::Create(RSContext* Context, const Type* T, const llvm::StringRef& TypeName, DataKind DK, bool Normalized) { |
| DataType DT = GetDataType(T); |
| |
| if((DT == DataTypeUnknown) || TypeName.empty()) |
| return NULL; |
| else |
| return new RSExportPrimitiveType(Context, TypeName, DT, DK, Normalized); |
| } |
| |
| RSExportPrimitiveType* RSExportPrimitiveType::Create(RSContext* Context, const Type* T, DataKind DK) { |
| llvm::StringRef TypeName; |
| if(RSExportType::NormalizeType(T, TypeName) && IsPrimitiveType(T)) |
| return Create(Context, T, TypeName, DK); |
| else |
| return NULL; |
| } |
| |
| RSExportType::ExportClass RSExportPrimitiveType::getClass() const { |
| return RSExportType::ExportClassPrimitive; |
| } |
| |
| const llvm::Type* RSExportPrimitiveType::convertToLLVMType() const { |
| llvm::LLVMContext& C = getRSContext()->getLLVMContext(); |
| |
| if(isRSObjectType()) { |
| /* struct { int* p; } __attribute__((packed, aligned(pointer_size))) which is <{ [1 x i32] }> in LLVM */ |
| if(RSObjectLLVMType == NULL) { |
| std::vector<const llvm::Type*> Elements; |
| Elements.push_back( llvm::ArrayType::get(llvm::Type::getInt32Ty(C), 1) ); |
| RSObjectLLVMType = llvm::StructType::get(C, Elements, true); |
| } |
| return RSObjectLLVMType; |
| } |
| |
| switch(mType) { |
| case DataTypeFloat32: |
| return llvm::Type::getFloatTy(C); |
| break; |
| |
| case DataTypeSigned8: |
| case DataTypeUnsigned8: |
| return llvm::Type::getInt8Ty(C); |
| break; |
| |
| case DataTypeSigned16: |
| case DataTypeUnsigned16: |
| case DataTypeUnsigned565: |
| case DataTypeUnsigned5551: |
| case DataTypeUnsigned4444: |
| return llvm::Type::getInt16Ty(C); |
| break; |
| |
| case DataTypeSigned32: |
| case DataTypeUnsigned32: |
| return llvm::Type::getInt32Ty(C); |
| break; |
| |
| case DataTypeBool: |
| return llvm::Type::getInt1Ty(C); |
| break; |
| |
| default: |
| assert(false && "Unknown data type"); |
| break; |
| } |
| |
| return NULL; |
| } |
| |
| /****************************** RSExportPointerType ******************************/ |
| |
| const Type* RSExportPointerType::IntegerType = NULL; |
| |
| RSExportPointerType* RSExportPointerType::Create(RSContext* Context, const PointerType* PT, const llvm::StringRef& TypeName) { |
| const Type* PointeeType = GET_POINTEE_TYPE(PT); |
| const RSExportType* PointeeET; |
| |
| if(PointeeType->getTypeClass() != Type::Pointer) { |
| PointeeET = RSExportType::Create(Context, PointeeType); |
| } else { |
| /* Double or higher dimension of pointer, export as int* */ |
| assert(IntegerType != NULL && "Built-in integer type is not set"); |
| PointeeET = RSExportPrimitiveType::Create(Context, IntegerType); |
| } |
| |
| if(PointeeET == NULL) { |
| printf("Failed to create type for pointee"); |
| return NULL; |
| } |
| |
| return new RSExportPointerType(Context, TypeName, PointeeET); |
| } |
| |
| RSExportType::ExportClass RSExportPointerType::getClass() const { |
| return RSExportType::ExportClassPointer; |
| } |
| |
| const llvm::Type* RSExportPointerType::convertToLLVMType() const { |
| const llvm::Type* PointeeType = mPointeeType->getLLVMType(); |
| return llvm::PointerType::getUnqual(PointeeType); |
| } |
| |
| /****************************** RSExportVectorType ******************************/ |
| const char* RSExportVectorType::VectorTypeNameStore[][3] = { |
| /* 0 */ { "char2", "char3", "char4" }, |
| /* 1 */ { "uchar2", "uchar3", "uchar4" }, |
| /* 2 */ { "short2", "short3", "short4" }, |
| /* 3 */ { "ushort2", "ushort3", "ushort4" }, |
| /* 4 */ { "int2", "int3", "int4" }, |
| /* 5 */ { "uint2", "uint3", "uint4" }, |
| /* 6 */ { "float2", "float3", "float4" }, |
| }; |
| |
| llvm::StringRef RSExportVectorType::GetTypeName(const ExtVectorType* EVT) { |
| const Type* ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); |
| |
| if((ElementType->getTypeClass() != Type::Builtin)) |
| return llvm::StringRef(); |
| |
| const BuiltinType* BT = UNSAFE_CAST_TYPE(BuiltinType, ElementType); |
| const char** BaseElement = NULL; |
| |
| switch(BT->getKind()) { |
| #define SLANG_RS_SUPPORT_BUILTIN_TYPE(builtin_type, type) \ |
| case builtin_type: \ |
| /* Compiler is smart enough to optimize following *big if branches* since they all become "constant comparison" after macro expansion */ \ |
| if(type == RSExportPrimitiveType::DataTypeSigned8) BaseElement = VectorTypeNameStore[0]; \ |
| else if(type == RSExportPrimitiveType::DataTypeUnsigned8) BaseElement = VectorTypeNameStore[1]; \ |
| else if(type == RSExportPrimitiveType::DataTypeSigned16) BaseElement = VectorTypeNameStore[2]; \ |
| else if(type == RSExportPrimitiveType::DataTypeUnsigned16) BaseElement = VectorTypeNameStore[3]; \ |
| else if(type == RSExportPrimitiveType::DataTypeSigned32) BaseElement = VectorTypeNameStore[4]; \ |
| else if(type == RSExportPrimitiveType::DataTypeUnsigned32) BaseElement = VectorTypeNameStore[5]; \ |
| else if(type == RSExportPrimitiveType::DataTypeFloat32) BaseElement = VectorTypeNameStore[6]; \ |
| else if(type == RSExportPrimitiveType::DataTypeBool) BaseElement = VectorTypeNameStore[0]; \ |
| break; |
| #include "slang_rs_export_type_support.inc" |
| |
| default: return llvm::StringRef(); break; |
| } |
| |
| if((BaseElement != NULL) && (EVT->getNumElements() > 1) && (EVT->getNumElements() <= 4)) |
| return BaseElement[EVT->getNumElements() - 2]; |
| else |
| return llvm::StringRef(); |
| } |
| |
| RSExportVectorType* RSExportVectorType::Create(RSContext* Context, const ExtVectorType* EVT, const llvm::StringRef& TypeName, DataKind DK, bool Normalized) { |
| assert(EVT != NULL && EVT->getTypeClass() == Type::ExtVector); |
| |
| const Type* ElementType = GET_EXT_VECTOR_ELEMENT_TYPE(EVT); |
| RSExportPrimitiveType::DataType DT = RSExportPrimitiveType::GetDataType(ElementType); |
| |
| if(DT != RSExportPrimitiveType::DataTypeUnknown) |
| return new RSExportVectorType(Context, TypeName, DT, DK, Normalized, EVT->getNumElements()); |
| else |
| printf("RSExportVectorType::Create : unsupported base element type\n"); |
| } |
| |
| RSExportType::ExportClass RSExportVectorType::getClass() const { |
| return RSExportType::ExportClassVector; |
| } |
| |
| const llvm::Type* RSExportVectorType::convertToLLVMType() const { |
| const llvm::Type* ElementType = RSExportPrimitiveType::convertToLLVMType(); |
| return llvm::VectorType::get(ElementType, getNumElement()); |
| } |
| |
| /****************************** RSExportRecordType ******************************/ |
| RSExportRecordType* RSExportRecordType::Create(RSContext* Context, const RecordType* RT, const llvm::StringRef& TypeName, bool mIsArtificial) { |
| assert(RT != NULL && RT->getTypeClass() == Type::Record); |
| |
| const RecordDecl* RD = RT->getDecl(); |
| assert(RD->isStruct()); |
| |
| RD = RD->getDefinition(); |
| if(RD == NULL) { |
| /* TODO: warning: actual struct definition isn't declared in this moudle */ |
| printf("RSExportRecordType::Create : this struct is not defined in this module."); |
| return NULL; |
| } |
| |
| RSExportRecordType* ERT = new RSExportRecordType(Context, TypeName, RD->hasAttr<PackedAttr>(), mIsArtificial); |
| unsigned int Index = 0; |
| |
| for(RecordDecl::field_iterator fit = RD->field_begin(); |
| fit != RD->field_end(); |
| fit++, Index++) |
| { |
| #define FAILED_CREATE_FIELD(err) do { \ |
| if(*err) \ |
| printf("RSExportRecordType::Create : failed to create field (%s)\n", err); \ |
| delete ERT; \ |
| return NULL; \ |
| } while(false) |
| /* FIXME: All fields should be primitive type */ |
| assert((*fit)->getKind() == Decl::Field); |
| FieldDecl* FD = *fit; |
| |
| /* We don't support bit field TODO: allow bitfield with size 8, 16, 32 */ |
| if(FD->isBitField()) |
| FAILED_CREATE_FIELD("bit field is not supported"); |
| |
| /* Type */ |
| RSExportType* ET = RSExportElement::CreateFromDecl(Context, FD); |
| |
| if(ET != NULL) |
| ERT->mFields.push_back( new Field(ET, FD->getName(), ERT, Index) ); |
| else |
| FAILED_CREATE_FIELD(FD->getName().str().c_str()); |
| #undef FAILED_CREATE_FIELD |
| } |
| |
| return ERT; |
| } |
| |
| RSExportType::ExportClass RSExportRecordType::getClass() const { |
| return RSExportType::ExportClassRecord; |
| } |
| |
| const llvm::Type* RSExportRecordType::convertToLLVMType() const { |
| std::vector<const llvm::Type*> FieldTypes; |
| |
| for(const_field_iterator FI = fields_begin(); |
| FI != fields_end(); |
| FI++) |
| { |
| const Field* F = *FI; |
| const RSExportType* FET = F->getType(); |
| |
| FieldTypes.push_back(FET->getLLVMType()); |
| } |
| |
| return llvm::StructType::get(getRSContext()->getLLVMContext(), FieldTypes, mIsPacked); |
| } |
| |
| /****************************** RSExportRecordType::Field ******************************/ |
| size_t RSExportRecordType::Field::getOffsetInParent() const { |
| /* Struct layout obtains below will be cached by LLVM */ |
| const llvm::StructLayout* SL = mParent->getRSContext()->getTargetData()->getStructLayout(static_cast<const llvm::StructType*>(mParent->getLLVMType())); |
| return SL->getElementOffset(mIndex); |
| } |
| |
| } /* namespace slang */ |