blob: e21358a311b0b0f37f69dd552102005c43d5d597 [file] [log] [blame]
#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 */