Add native support for (AO)SOA data layout.
There's now a SOA variability class (in addition to uniform,
varying, and unbound variability); the SOA factor must be a
positive power of 2.
When applied to a type, the leaf elements of the type (i.e.
atomic types, pointer types, and enum types) are widened out
into arrays of the given SOA factor. For example, given
struct Point { float x, y, z; };
Then "soa<8> Point" has a memory layout of "float x[8], y[8],
z[8]".
Furthermore, array indexing syntax has been augmented so that
when indexing into arrays of SOA-variability data, the two-stage
indexing (first into the array of soa<> elements and then into
the leaf arrays of SOA data) is performed automatically.
This commit is contained in:
490
type.cpp
490
type.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2011, Intel Corporation
|
||||
Copyright (c) 2010-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -66,6 +66,34 @@ lShouldPrintName(const std::string &name) {
|
||||
}
|
||||
|
||||
|
||||
/** Utility routine to create a llvm DIArray type of the given number of
|
||||
the given element type. */
|
||||
static llvm::DIType
|
||||
lCreateDIArray(llvm::DIType eltType, int count) {
|
||||
int lowerBound = 0, upperBound = count-1;
|
||||
|
||||
if (count == 0) {
|
||||
// unsized array -> indicate with low > high
|
||||
lowerBound = 1;
|
||||
upperBound = 0;
|
||||
}
|
||||
|
||||
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(lowerBound, upperBound);
|
||||
std::vector<llvm::Value *> subs;
|
||||
subs.push_back(sub);
|
||||
#ifdef LLVM_2_9
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(&subs[0], subs.size());
|
||||
#else
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(subs);
|
||||
#endif
|
||||
|
||||
uint64_t size = eltType.getSizeInBits() * count;
|
||||
uint64_t align = eltType.getAlignInBits();
|
||||
|
||||
return m->diBuilder->createArrayType(size, align, eltType, subArray);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Variability
|
||||
|
||||
@@ -275,8 +303,15 @@ AtomicType::GetAsUnboundVariabilityType() const {
|
||||
if (variability == Variability::Unbound)
|
||||
return this;
|
||||
return new AtomicType(basicType, Variability::Unbound, isConst);
|
||||
}
|
||||
|
||||
|
||||
const AtomicType *
|
||||
AtomicType::GetAsSOAType(int width) const {
|
||||
Assert(this != AtomicType::Void);
|
||||
if (variability == Variability(Variability::SOA, width))
|
||||
return this;
|
||||
return new AtomicType(basicType, Unbound, isConst);
|
||||
return new AtomicType(basicType, Variability(Variability::SOA, width), isConst);
|
||||
}
|
||||
|
||||
|
||||
@@ -372,6 +407,13 @@ AtomicType::GetCDeclaration(const std::string &name) const {
|
||||
ret += " ";
|
||||
ret += name;
|
||||
}
|
||||
|
||||
if (variability == Variability::SOA) {
|
||||
char buf[32];
|
||||
sprintf(buf, "[%d]", variability.soaWidth);
|
||||
ret += buf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -380,31 +422,38 @@ LLVM_TYPE_CONST llvm::Type *
|
||||
AtomicType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
Assert(variability.type != Variability::Unbound);
|
||||
bool isUniform = (variability == Variability::Uniform);
|
||||
bool isVarying = (variability == Variability::Varying);
|
||||
|
||||
switch (basicType) {
|
||||
case TYPE_VOID:
|
||||
return llvm::Type::getVoidTy(*ctx);
|
||||
case TYPE_BOOL:
|
||||
return isUniform ? LLVMTypes::BoolType : LLVMTypes::BoolVectorType;
|
||||
case TYPE_INT8:
|
||||
case TYPE_UINT8:
|
||||
return isUniform ? LLVMTypes::Int8Type : LLVMTypes::Int8VectorType;
|
||||
case TYPE_INT16:
|
||||
case TYPE_UINT16:
|
||||
return isUniform ? LLVMTypes::Int16Type : LLVMTypes::Int16VectorType;
|
||||
case TYPE_INT32:
|
||||
case TYPE_UINT32:
|
||||
return isUniform ? LLVMTypes::Int32Type : LLVMTypes::Int32VectorType;
|
||||
case TYPE_FLOAT:
|
||||
return isUniform ? LLVMTypes::FloatType : LLVMTypes::FloatVectorType;
|
||||
case TYPE_INT64:
|
||||
case TYPE_UINT64:
|
||||
return isUniform ? LLVMTypes::Int64Type : LLVMTypes::Int64VectorType;
|
||||
case TYPE_DOUBLE:
|
||||
return isUniform ? LLVMTypes::DoubleType : LLVMTypes::DoubleVectorType;
|
||||
default:
|
||||
FATAL("logic error in AtomicType::LLVMType");
|
||||
return NULL;
|
||||
if (isUniform || isVarying) {
|
||||
switch (basicType) {
|
||||
case TYPE_VOID:
|
||||
return llvm::Type::getVoidTy(*ctx);
|
||||
case TYPE_BOOL:
|
||||
return isUniform ? LLVMTypes::BoolType : LLVMTypes::BoolVectorType;
|
||||
case TYPE_INT8:
|
||||
case TYPE_UINT8:
|
||||
return isUniform ? LLVMTypes::Int8Type : LLVMTypes::Int8VectorType;
|
||||
case TYPE_INT16:
|
||||
case TYPE_UINT16:
|
||||
return isUniform ? LLVMTypes::Int16Type : LLVMTypes::Int16VectorType;
|
||||
case TYPE_INT32:
|
||||
case TYPE_UINT32:
|
||||
return isUniform ? LLVMTypes::Int32Type : LLVMTypes::Int32VectorType;
|
||||
case TYPE_FLOAT:
|
||||
return isUniform ? LLVMTypes::FloatType : LLVMTypes::FloatVectorType;
|
||||
case TYPE_INT64:
|
||||
case TYPE_UINT64:
|
||||
return isUniform ? LLVMTypes::Int64Type : LLVMTypes::Int64VectorType;
|
||||
case TYPE_DOUBLE:
|
||||
return isUniform ? LLVMTypes::DoubleType : LLVMTypes::DoubleVectorType;
|
||||
default:
|
||||
FATAL("logic error in AtomicType::LLVMType");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ArrayType at(GetAsUniformType(), variability.soaWidth);
|
||||
return at.LLVMType(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,7 +515,7 @@ AtomicType::GetDIType(llvm::DIDescriptor scope) const {
|
||||
return llvm::DIType();
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (variability == Variability::Varying) {
|
||||
llvm::DIType unifType = GetAsUniformType()->GetDIType(scope);
|
||||
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1);
|
||||
#ifdef LLVM_2_9
|
||||
@@ -479,6 +528,11 @@ AtomicType::GetDIType(llvm::DIDescriptor scope) const {
|
||||
uint64_t align = unifType.getAlignInBits() * g->target.vectorWidth;
|
||||
return m->diBuilder->createVectorType(size, align, unifType, subArray);
|
||||
}
|
||||
else {
|
||||
Assert(variability == Variability::SOA);
|
||||
ArrayType at(GetAsUniformType(), variability.soaWidth);
|
||||
return at.GetDIType(scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -590,6 +644,18 @@ EnumType::GetAsUnboundVariabilityType() const {
|
||||
}
|
||||
|
||||
|
||||
const EnumType *
|
||||
EnumType::GetAsSOAType(int width) const {
|
||||
if (GetSOAWidth() == width)
|
||||
return this;
|
||||
else {
|
||||
EnumType *enumType = new EnumType(*this);
|
||||
enumType->variability = Variability(Variability::SOA, width);
|
||||
return enumType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const EnumType *
|
||||
EnumType::GetAsConstType() const {
|
||||
if (isConst)
|
||||
@@ -657,6 +723,13 @@ EnumType::GetCDeclaration(const std::string &varName) const {
|
||||
ret += " ";
|
||||
ret += varName;
|
||||
}
|
||||
|
||||
if (variability == Variability::SOA) {
|
||||
char buf[32];
|
||||
sprintf(buf, "[%d]", variability.soaWidth);
|
||||
ret += buf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -670,6 +743,10 @@ EnumType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
return LLVMTypes::Int32Type;
|
||||
case Variability::Varying:
|
||||
return LLVMTypes::Int32VectorType;
|
||||
case Variability::SOA: {
|
||||
ArrayType at(AtomicType::UniformInt32, variability.soaWidth);
|
||||
return at.LLVMType(ctx);
|
||||
}
|
||||
default:
|
||||
FATAL("Unexpected variability in EnumType::LLVMType()");
|
||||
return NULL;
|
||||
@@ -705,19 +782,30 @@ EnumType::GetDIType(llvm::DIDescriptor scope) const {
|
||||
32 /* size in bits */,
|
||||
32 /* align in bits */,
|
||||
elementArray);
|
||||
if (IsUniformType())
|
||||
return diType;
|
||||
|
||||
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1);
|
||||
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform:
|
||||
return diType;
|
||||
case Variability::Varying: {
|
||||
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(0, g->target.vectorWidth-1);
|
||||
#ifdef LLVM_2_9
|
||||
llvm::Value *suba[] = { sub };
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(suba, 1);
|
||||
llvm::Value *suba[] = { sub };
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(suba, 1);
|
||||
#else
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub);
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(sub);
|
||||
#endif // !LLVM_2_9
|
||||
uint64_t size = diType.getSizeInBits() * g->target.vectorWidth;
|
||||
uint64_t align = diType.getAlignInBits() * g->target.vectorWidth;
|
||||
return m->diBuilder->createVectorType(size, align, diType, subArray);
|
||||
uint64_t size = diType.getSizeInBits() * g->target.vectorWidth;
|
||||
uint64_t align = diType.getAlignInBits() * g->target.vectorWidth;
|
||||
return m->diBuilder->createVectorType(size, align, diType, subArray);
|
||||
}
|
||||
case Variability::SOA: {
|
||||
return lCreateDIArray(diType, variability.soaWidth);
|
||||
}
|
||||
default:
|
||||
FATAL("Unexpected variability in EnumType::GetDIType()");
|
||||
return llvm::DIType();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -746,8 +834,9 @@ PointerType *PointerType::Void =
|
||||
new PointerType(AtomicType::Void, Variability(Variability::Uniform), false);
|
||||
|
||||
|
||||
PointerType::PointerType(const Type *t, Variability v, bool ic)
|
||||
: variability(v), isConst(ic) {
|
||||
PointerType::PointerType(const Type *t, Variability v, bool ic, bool is,
|
||||
bool fr)
|
||||
: variability(v), isConst(ic), isSlice(is), isFrozen(fr) {
|
||||
baseType = t;
|
||||
}
|
||||
|
||||
@@ -819,6 +908,7 @@ PointerType::GetAsVaryingType() const {
|
||||
return this;
|
||||
else
|
||||
return new PointerType(baseType, Variability(Variability::Varying),
|
||||
isConst, isSlice, isFrozen);
|
||||
}
|
||||
|
||||
|
||||
@@ -828,6 +918,7 @@ PointerType::GetAsUniformType() const {
|
||||
return this;
|
||||
else
|
||||
return new PointerType(baseType, Variability(Variability::Uniform),
|
||||
isConst, isSlice, isFrozen);
|
||||
}
|
||||
|
||||
|
||||
@@ -837,6 +928,77 @@ PointerType::GetAsUnboundVariabilityType() const {
|
||||
return this;
|
||||
else
|
||||
return new PointerType(baseType, Variability(Variability::Unbound),
|
||||
isConst, isSlice, isFrozen);
|
||||
}
|
||||
|
||||
|
||||
const PointerType *
|
||||
PointerType::GetAsSOAType(int width) const {
|
||||
if (GetSOAWidth() == width)
|
||||
return this;
|
||||
else
|
||||
return new PointerType(baseType, Variability(Variability::SOA, width),
|
||||
isConst, isSlice, isFrozen);
|
||||
}
|
||||
|
||||
|
||||
const PointerType *
|
||||
PointerType::GetAsSlice() const {
|
||||
if (isSlice)
|
||||
return this;
|
||||
return new PointerType(baseType, variability, isConst, true);
|
||||
}
|
||||
|
||||
|
||||
const PointerType *
|
||||
PointerType::GetAsNonSlice() const {
|
||||
if (isSlice == false)
|
||||
return this;
|
||||
return new PointerType(baseType, variability, isConst, false);
|
||||
}
|
||||
|
||||
|
||||
const PointerType *
|
||||
PointerType::GetAsFrozenSlice() const {
|
||||
if (isFrozen)
|
||||
return this;
|
||||
return new PointerType(baseType, variability, isConst, true, true);
|
||||
}
|
||||
|
||||
|
||||
/** Returns a structure corresponding to the pointer representation for
|
||||
slice pointers; the first member of this structure is a uniform or
|
||||
varying pointer, and the second element is either a uniform or varying
|
||||
int32.
|
||||
*/
|
||||
const StructType *
|
||||
PointerType::GetSliceStructType() const {
|
||||
Assert(isSlice == true);
|
||||
|
||||
std::vector<const Type *> eltTypes;
|
||||
eltTypes.push_back(GetAsNonSlice());
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform:
|
||||
eltTypes.push_back(AtomicType::UniformInt32);
|
||||
break;
|
||||
case Variability::Varying:
|
||||
eltTypes.push_back(AtomicType::VaryingInt32);
|
||||
break;
|
||||
default:
|
||||
FATAL("Unexpected variability in PointerType::GetSliceStructType()");
|
||||
}
|
||||
|
||||
std::vector<std::string> eltNames;
|
||||
std::vector<SourcePos> eltPos;
|
||||
|
||||
eltNames.push_back("ptr");
|
||||
eltNames.push_back("offset");
|
||||
|
||||
eltPos.push_back(SourcePos());
|
||||
eltPos.push_back(SourcePos());
|
||||
|
||||
return new StructType("__ptr_slice_tmp", eltTypes, eltNames, eltPos, isConst,
|
||||
Variability::Uniform, SourcePos());
|
||||
}
|
||||
|
||||
|
||||
@@ -853,6 +1015,7 @@ PointerType::ResolveUnboundVariability(Variability v) const {
|
||||
const Type *resolvedBaseType =
|
||||
baseType->ResolveUnboundVariability(Variability::Uniform);
|
||||
return new PointerType(resolvedBaseType, ptrVariability, isConst, isSlice,
|
||||
isFrozen);
|
||||
}
|
||||
|
||||
|
||||
@@ -861,7 +1024,7 @@ PointerType::GetAsConstType() const {
|
||||
if (isConst == true)
|
||||
return this;
|
||||
else
|
||||
return new PointerType(baseType, variability, true);
|
||||
return new PointerType(baseType, variability, true, isSlice);
|
||||
}
|
||||
|
||||
|
||||
@@ -870,7 +1033,7 @@ PointerType::GetAsNonConstType() const {
|
||||
if (isConst == false)
|
||||
return this;
|
||||
else
|
||||
return new PointerType(baseType, variability, false);
|
||||
return new PointerType(baseType, variability, false, isSlice);
|
||||
}
|
||||
|
||||
|
||||
@@ -885,6 +1048,8 @@ PointerType::GetString() const {
|
||||
|
||||
ret += std::string(" * ");
|
||||
if (isConst) ret += "const ";
|
||||
if (isSlice) ret += "slice ";
|
||||
if (isFrozen) ret += "/*frozen*/ ";
|
||||
ret += variability.GetString();
|
||||
|
||||
return ret;
|
||||
@@ -900,13 +1065,19 @@ PointerType::Mangle() const {
|
||||
}
|
||||
|
||||
std::string ret = variability.MangleString() + std::string("<");
|
||||
if (isSlice || isFrozen) ret += "-";
|
||||
if (isSlice) ret += "s";
|
||||
if (isFrozen) ret += "f";
|
||||
if (isSlice || isFrozen) ret += "-";
|
||||
return ret + baseType->Mangle() + std::string(">");
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
PointerType::GetCDeclaration(const std::string &name) const {
|
||||
if (variability != Uniform) {
|
||||
if (isSlice ||
|
||||
(variability != Variability::Uniform &&
|
||||
variability != Variability::SOA)) {
|
||||
Assert(m->errorCount > 0);
|
||||
return "";
|
||||
}
|
||||
@@ -921,6 +1092,13 @@ PointerType::GetCDeclaration(const std::string &name) const {
|
||||
if (isConst) ret += " const";
|
||||
ret += std::string(" ");
|
||||
ret += name;
|
||||
|
||||
if (variability == Variability::SOA) {
|
||||
char buf[32];
|
||||
sprintf(buf, "[%d]", variability.soaWidth);
|
||||
ret += buf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -932,52 +1110,41 @@ PointerType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (variability == Varying)
|
||||
if (isSlice)
|
||||
// Slice pointers are represented as a structure with a pointer and
|
||||
// an integer offset; the corresponding ispc type is returned by
|
||||
// GetSliceStructType().
|
||||
return GetSliceStructType()->LLVMType(ctx);
|
||||
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform: {
|
||||
LLVM_TYPE_CONST llvm::Type *ptype = NULL;
|
||||
const FunctionType *ftype = dynamic_cast<const FunctionType *>(baseType);
|
||||
if (ftype != NULL)
|
||||
// Get the type of the function variant that takes the mask as the
|
||||
// last parameter--i.e. we don't allow taking function pointers of
|
||||
// exported functions.
|
||||
ptype = llvm::PointerType::get(ftype->LLVMFunctionType(ctx, true), 0);
|
||||
else {
|
||||
if (baseType == AtomicType::Void)
|
||||
ptype = LLVMTypes::VoidPointerType;
|
||||
else
|
||||
ptype = llvm::PointerType::get(baseType->LLVMType(ctx), 0);
|
||||
}
|
||||
return ptype;
|
||||
}
|
||||
case Variability::Varying:
|
||||
// always the same, since we currently use int vectors for varying
|
||||
// pointers
|
||||
return LLVMTypes::VoidPointerVectorType;
|
||||
|
||||
LLVM_TYPE_CONST llvm::Type *ptype = NULL;
|
||||
const FunctionType *ftype = dynamic_cast<const FunctionType *>(baseType);
|
||||
if (ftype != NULL)
|
||||
// Get the type of the function variant that takes the mask as the
|
||||
// last parameter--i.e. we don't allow taking function pointers of
|
||||
// exported functions.
|
||||
ptype = llvm::PointerType::get(ftype->LLVMFunctionType(ctx, true), 0);
|
||||
else {
|
||||
if (Type::Equal(baseType, AtomicType::Void))
|
||||
ptype = LLVMTypes::VoidPointerType;
|
||||
else
|
||||
ptype = llvm::PointerType::get(baseType->LLVMType(ctx), 0);
|
||||
case Variability::SOA: {
|
||||
ArrayType at(GetAsUniformType(), variability.soaWidth);
|
||||
return at.LLVMType(ctx);
|
||||
}
|
||||
|
||||
return ptype;
|
||||
}
|
||||
|
||||
|
||||
static llvm::DIType
|
||||
lCreateDIArray(llvm::DIType eltType, int count) {
|
||||
int lowerBound = 0, upperBound = count-1;
|
||||
|
||||
if (count == 0) {
|
||||
// unsized array -> indicate with low > high
|
||||
lowerBound = 1;
|
||||
upperBound = 0;
|
||||
default:
|
||||
FATAL("Unexpected variability in PointerType::LLVMType()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
llvm::Value *sub = m->diBuilder->getOrCreateSubrange(lowerBound, upperBound);
|
||||
std::vector<llvm::Value *> subs;
|
||||
subs.push_back(sub);
|
||||
#ifdef LLVM_2_9
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(&subs[0], subs.size());
|
||||
#else
|
||||
llvm::DIArray subArray = m->diBuilder->getOrCreateArray(subs);
|
||||
#endif
|
||||
|
||||
uint64_t size = eltType.getSizeInBits() * count;
|
||||
uint64_t align = eltType.getAlignInBits();
|
||||
|
||||
return m->diBuilder->createArrayType(size, align, eltType, subArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -999,6 +1166,10 @@ PointerType::GetDIType(llvm::DIDescriptor scope) const {
|
||||
bitsSize);
|
||||
return lCreateDIArray(eltType, g->target.vectorWidth);
|
||||
}
|
||||
case Variability::SOA: {
|
||||
ArrayType at(GetAsUniformType(), variability.soaWidth);
|
||||
return at.GetDIType(scope);
|
||||
}
|
||||
default:
|
||||
FATAL("Unexpected variability in PointerType::GetDIType()");
|
||||
return llvm::DIType();
|
||||
@@ -1120,6 +1291,16 @@ ArrayType::GetAsUnboundVariabilityType() const {
|
||||
}
|
||||
|
||||
|
||||
const ArrayType *
|
||||
ArrayType::GetAsSOAType(int width) const {
|
||||
if (child == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
return new ArrayType(child->GetAsSOAType(width), numElements);
|
||||
}
|
||||
|
||||
|
||||
const ArrayType *
|
||||
ArrayType::ResolveUnboundVariability(Variability v) const {
|
||||
if (child == NULL) {
|
||||
@@ -1220,6 +1401,10 @@ ArrayType::GetCDeclaration(const std::string &name) const {
|
||||
Assert(m->errorCount > 0);
|
||||
return "";
|
||||
}
|
||||
|
||||
int soaWidth = base->GetSOAWidth();
|
||||
base = base->GetAsUniformType();
|
||||
|
||||
std::string s = base->GetCDeclaration(name);
|
||||
|
||||
const ArrayType *at = this;
|
||||
@@ -1232,6 +1417,13 @@ ArrayType::GetCDeclaration(const std::string &name) const {
|
||||
s += std::string("[") + std::string(buf) + std::string("]");
|
||||
at = dynamic_cast<const ArrayType *>(at->child);
|
||||
}
|
||||
|
||||
if (soaWidth > 0) {
|
||||
char buf[16];
|
||||
sprintf(buf, "[%d]", soaWidth);
|
||||
s += buf;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1393,6 +1585,12 @@ VectorType::GetAsUnboundVariabilityType() const {
|
||||
}
|
||||
|
||||
|
||||
const VectorType *
|
||||
VectorType::GetAsSOAType(int width) const {
|
||||
return new VectorType(base->GetAsSOAType(width), numElements);
|
||||
}
|
||||
|
||||
|
||||
const VectorType *
|
||||
VectorType::ResolveUnboundVariability(Variability v) const {
|
||||
return new VectorType(base->ResolveUnboundVariability(v), numElements);
|
||||
@@ -1452,6 +1650,11 @@ VectorType::GetElementType() const {
|
||||
|
||||
LLVM_TYPE_CONST llvm::Type *
|
||||
VectorType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
if (base == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLVM_TYPE_CONST llvm::Type *bt = base->LLVMType(ctx);
|
||||
if (!bt)
|
||||
return NULL;
|
||||
@@ -1464,10 +1667,16 @@ VectorType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
// registers so that e.g. if we want to add two uniform 4 float
|
||||
// vectors, that is turned into a single addps on SSE.
|
||||
return llvm::VectorType::get(bt, getVectorMemoryCount());
|
||||
else
|
||||
else if (base->IsVaryingType())
|
||||
// varying types are already laid out to fill HW vector registers,
|
||||
// so a vector type here is just expanded out as an llvm array.
|
||||
return llvm::ArrayType::get(bt, getVectorMemoryCount());
|
||||
else if (base->IsSOAType())
|
||||
return llvm::ArrayType::get(bt, numElements);
|
||||
else {
|
||||
FATAL("Unexpected variability in VectorType::LLVMType()");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1491,7 +1700,16 @@ VectorType::GetDIType(llvm::DIDescriptor scope) const {
|
||||
if (IsUniformType())
|
||||
align = 4 * g->target.nativeVectorWidth;
|
||||
|
||||
return m->diBuilder->createVectorType(sizeBits, align, eltType, subArray);
|
||||
if (IsUniformType() || IsVaryingType())
|
||||
return m->diBuilder->createVectorType(sizeBits, align, eltType, subArray);
|
||||
else if (IsSOAType()) {
|
||||
ArrayType at(base, numElements);
|
||||
return at.GetDIType(scope);
|
||||
}
|
||||
else {
|
||||
FATAL("Unexpected variability in VectorType::GetDIType()");
|
||||
return llvm::DIType();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1499,7 +1717,7 @@ int
|
||||
VectorType::getVectorMemoryCount() const {
|
||||
if (base->IsVaryingType())
|
||||
return numElements;
|
||||
else {
|
||||
else if (base->IsUniformType()) {
|
||||
int nativeWidth = g->target.nativeVectorWidth;
|
||||
if (Type::Equal(base->GetAsUniformType(), AtomicType::UniformInt64) ||
|
||||
Type::Equal(base->GetAsUniformType(), AtomicType::UniformUInt64) ||
|
||||
@@ -1512,6 +1730,14 @@ VectorType::getVectorMemoryCount() const {
|
||||
// nativeWidth
|
||||
return (numElements + (nativeWidth - 1)) & ~(nativeWidth-1);
|
||||
}
|
||||
else if (base->IsSOAType()) {
|
||||
FATAL("VectorType SOA getVectorMemoryCount");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
FATAL("Unexpected variability in VectorType::getVectorMemoryCount()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1599,6 +1825,19 @@ StructType::GetAsUnboundVariabilityType() const {
|
||||
}
|
||||
|
||||
|
||||
const StructType *
|
||||
StructType::GetAsSOAType(int width) const {
|
||||
if (GetSOAWidth() == width)
|
||||
return this;
|
||||
|
||||
if (checkIfCanBeSOA(this) == false)
|
||||
return NULL;
|
||||
|
||||
return new StructType(name, elementTypes, elementNames, elementPositions,
|
||||
isConst, Variability(Variability::SOA, width), pos);
|
||||
}
|
||||
|
||||
|
||||
const StructType *
|
||||
StructType::ResolveUnboundVariability(Variability v) const {
|
||||
Assert(v != Variability::Unbound);
|
||||
@@ -1686,6 +1925,15 @@ StructType::GetCDeclaration(const std::string &n) const {
|
||||
ret += std::string("struct ") + name;
|
||||
if (lShouldPrintName(n))
|
||||
ret += std::string(" ") + n;
|
||||
|
||||
if (variability.soaWidth > 0) {
|
||||
char buf[32];
|
||||
// This has to match the naming scheme used in lEmitStructDecls()
|
||||
// in module.cpp
|
||||
sprintf(buf, "_SOA%d", variability.soaWidth);
|
||||
ret += buf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1793,6 +2041,35 @@ StructType::GetElementNumber(const std::string &n) const {
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StructType::checkIfCanBeSOA(const StructType *st) {
|
||||
bool ok = true;
|
||||
for (int i = 0; i < (int)st->elementTypes.size(); ++i) {
|
||||
const Type *eltType = st->elementTypes[i];
|
||||
const StructType *childStructType =
|
||||
dynamic_cast<const StructType *>(eltType);
|
||||
|
||||
if (childStructType != NULL)
|
||||
ok &= checkIfCanBeSOA(childStructType);
|
||||
else if (eltType->HasUnboundVariability() == false) {
|
||||
Error(st->elementPositions[i], "Unable to apply SOA conversion to "
|
||||
"struct due to \"%s\" member \"%s\" with bound \"%s\" "
|
||||
"variability.", eltType->GetString().c_str(),
|
||||
st->elementNames[i].c_str(),
|
||||
eltType->IsUniformType() ? "uniform" : "varying");
|
||||
ok = false;
|
||||
}
|
||||
else if (dynamic_cast<const ReferenceType *>(eltType)) {
|
||||
Error(st->elementPositions[i], "Unable to apply SOA conversion to "
|
||||
"struct due to member \"%s\" with reference type \"%s\".",
|
||||
st->elementNames[i].c_str(), eltType->GetString().c_str());
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ReferenceType
|
||||
|
||||
@@ -1913,6 +2190,13 @@ ReferenceType::GetAsUnboundVariabilityType() const {
|
||||
}
|
||||
|
||||
|
||||
const Type *
|
||||
ReferenceType::GetAsSOAType(int width) const {
|
||||
// FIXME: is this right?
|
||||
return new ArrayType(this, width);
|
||||
}
|
||||
|
||||
|
||||
const ReferenceType *
|
||||
ReferenceType::ResolveUnboundVariability(Variability v) const {
|
||||
if (targetType == NULL) {
|
||||
@@ -2126,6 +2410,13 @@ FunctionType::GetAsUnboundVariabilityType() const {
|
||||
}
|
||||
|
||||
|
||||
const Type *
|
||||
FunctionType::GetAsSOAType(int width) const {
|
||||
FATAL("FunctionType::GetAsSOAType() shouldn't be called");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const FunctionType *
|
||||
FunctionType::ResolveUnboundVariability(Variability v) const {
|
||||
if (returnType == NULL) {
|
||||
@@ -2527,6 +2818,14 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Type::IsBasicType(const Type *type) {
|
||||
return (dynamic_cast<const AtomicType *>(type) != NULL ||
|
||||
dynamic_cast<const EnumType *>(type) != NULL ||
|
||||
dynamic_cast<const PointerType *>(type) != NULL);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
|
||||
if (a == NULL || b == NULL)
|
||||
@@ -2579,13 +2878,26 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
|
||||
return false;
|
||||
if (sta->GetStructName() != stb->GetStructName())
|
||||
return false;
|
||||
if (sta->GetVariability() != stb->GetVariability())
|
||||
return false;
|
||||
for (int i = 0; i < sta->GetElementCount(); ++i)
|
||||
// FIXME: is this redundant now?
|
||||
if (!lCheckTypeEquality(sta->GetElementType(i), stb->GetElementType(i),
|
||||
ignoreConst))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const PointerType *pta = dynamic_cast<const PointerType *>(a);
|
||||
const PointerType *ptb = dynamic_cast<const PointerType *>(b);
|
||||
if (pta != NULL && ptb != NULL)
|
||||
return (pta->IsUniformType() == ptb->IsUniformType() &&
|
||||
pta->IsSlice() == ptb->IsSlice() &&
|
||||
pta->IsFrozenSlice() == ptb->IsFrozenSlice() &&
|
||||
lCheckTypeEquality(pta->GetBaseType(), ptb->GetBaseType(),
|
||||
ignoreConst));
|
||||
|
||||
const ReferenceType *rta = dynamic_cast<const ReferenceType *>(a);
|
||||
const ReferenceType *rtb = dynamic_cast<const ReferenceType *>(b);
|
||||
if (rta != NULL && rtb != NULL)
|
||||
@@ -2617,14 +2929,6 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const PointerType *pta = dynamic_cast<const PointerType *>(a);
|
||||
const PointerType *ptb = dynamic_cast<const PointerType *>(b);
|
||||
if (pta != NULL && ptb != NULL)
|
||||
return (pta->IsConstType() == ptb->IsConstType() &&
|
||||
pta->IsUniformType() == ptb->IsUniformType() &&
|
||||
lCheckTypeEquality(pta->GetBaseType(), ptb->GetBaseType(),
|
||||
ignoreConst));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user