Add support for enums.

This commit is contained in:
Matt Pharr
2011-07-17 16:43:05 +02:00
parent 17e5c8b7c2
commit f0f876c3ec
23 changed files with 1031 additions and 251 deletions

283
type.cpp
View File

@@ -410,6 +410,223 @@ AtomicType::GetDIType(llvm::DIDescriptor scope) const {
}
///////////////////////////////////////////////////////////////////////////
// EnumType
EnumType::EnumType(SourcePos p)
: pos(p) {
// name = "/* (anonymous) */";
isConst = false;
isUniform = false;
}
EnumType::EnumType(const char *n, SourcePos p)
: pos(p), name(n) {
isConst = false;
isUniform = false;
}
bool
EnumType::IsUniformType() const {
return isUniform;
}
bool
EnumType::IsBoolType() const {
return false;
}
bool
EnumType::IsFloatType() const {
return false;
}
bool
EnumType::IsIntType() const {
return true;
}
bool
EnumType::IsUnsignedType() const {
return true;
}
bool
EnumType::IsConstType() const {
return isConst;
}
const EnumType *
EnumType::GetBaseType() const {
return this;
}
const EnumType *
EnumType::GetAsVaryingType() const {
if (IsVaryingType())
return this;
else {
EnumType *enumType = new EnumType(*this);
enumType->isUniform = false;
return enumType;
}
}
const EnumType *
EnumType::GetAsUniformType() const {
if (IsUniformType())
return this;
else {
EnumType *enumType = new EnumType(*this);
enumType->isUniform = true;
return enumType;
}
}
const Type *
EnumType::GetSOAType(int width) const {
assert(width > 0);
return new ArrayType(this, width);
}
const EnumType *
EnumType::GetAsConstType() const {
if (isConst)
return this;
else {
EnumType *enumType = new EnumType(*this);
enumType->isConst = true;
return enumType;
}
}
const EnumType *
EnumType::GetAsNonConstType() const {
if (!isConst)
return this;
else {
EnumType *enumType = new EnumType(*this);
enumType->isConst = false;
return enumType;
}
}
std::string
EnumType::GetString() const {
std::string ret;
if (isConst) ret += "const ";
if (isUniform) ret += "uniform ";
ret += "enum ";
if (name.size())
ret += name;
return ret;
}
std::string
EnumType::Mangle() const {
std::string ret = std::string("enum[") + name + std::string("]");
return ret;
}
std::string
EnumType::GetCDeclaration(const std::string &varName) const {
std::string ret;
if (isConst) ret += "const ";
ret += "enum";
if (name.size())
ret += std::string(" ") + name;
if (lShouldPrintName(varName)) {
ret += " ";
ret += varName;
}
return ret;
}
LLVM_TYPE_CONST llvm::Type *
EnumType::LLVMType(llvm::LLVMContext *ctx) const {
return isUniform ? LLVMTypes::Int32Type : LLVMTypes::Int32VectorType;
}
llvm::DIType
EnumType::GetDIType(llvm::DIDescriptor scope) const {
#ifdef LLVM_2_8
FATAL("debug info not supported in llvm 2.8");
return llvm::DIType();
#else
std::vector<llvm::Value *> enumeratorDescriptors;
for (unsigned int i = 0; i < enumerators.size(); ++i) {
unsigned int enumeratorValue;
assert(enumerators[i]->constValue != NULL);
int count = enumerators[i]->constValue->AsUInt32(&enumeratorValue);
assert(count == 1);
llvm::Value *descriptor =
m->diBuilder->createEnumerator(enumerators[i]->name, enumeratorValue);
enumeratorDescriptors.push_back(descriptor);
}
llvm::DIArray elementArray =
m->diBuilder->getOrCreateArray(&enumeratorDescriptors[0],
enumeratorDescriptors.size());
llvm::DIFile diFile = pos.GetDIFile();
llvm::DIType diType =
m->diBuilder->createEnumerationType(scope, name, diFile, pos.first_line,
32 /* size in bits */,
32 /* align in bits */,
elementArray);
if (IsUniformType())
return diType;
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);
#else
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);
#endif // !LLVM_2_8
}
void
EnumType::SetEnumerators(const std::vector<Symbol *> &e) {
enumerators = e;
}
int
EnumType::GetEnumeratorCount() const {
return (int)enumerators.size();
}
const Symbol *
EnumType::GetEnumerator(int i) const {
return enumerators[i];
}
///////////////////////////////////////////////////////////////////////////
// SequentialType
@@ -1462,6 +1679,7 @@ FunctionType::GetBaseType() const {
return NULL;
}
const Type *
FunctionType::GetAsVaryingType() const {
FATAL("FunctionType::GetAsVaryingType shouldn't be called");
@@ -1735,54 +1953,95 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
// TODO: what do we need to do about references here, if anything??
// Now all we can do is promote atomic types...
const AtomicType *at0 = dynamic_cast<const AtomicType *>(t0->GetReferenceTarget());
const AtomicType *at1 = dynamic_cast<const AtomicType *>(t1->GetReferenceTarget());
if (!at0 || !at1) {
assert(reason);
const EnumType *et0 = dynamic_cast<const EnumType *>(t0->GetReferenceTarget());
const EnumType *et1 = dynamic_cast<const EnumType *>(t1->GetReferenceTarget());
if (et0 != NULL && et1 != NULL) {
// Two different enum types -> make them uint32s...
assert(et0->IsVaryingType() == et1->IsVaryingType());
return et0->IsVaryingType() ? AtomicType::VaryingUInt32 :
AtomicType::UniformUInt32;
}
else if (et0 != NULL) {
if (at1 != NULL)
// Enum type and atomic type -> convert the enum to the atomic type
// TODO: should we return uint32 here, unless the atomic type is
// a 64-bit atomic type, in which case we return that?
return at1;
else {
Error(pos, "Implicit conversion from enum type \"%s\" to "
"non-atomic type \"%s\" for %s not possible.",
t0->GetString().c_str(), t1->GetString().c_str(), reason);
return NULL;
}
}
else if (et1 != NULL) {
if (at0 != NULL)
// Enum type and atomic type; see TODO above here as well...
return at0;
else {
Error(pos, "Implicit conversion from enum type \"%s\" to "
"non-atomic type \"%s\" for %s not possible.",
t1->GetString().c_str(), t0->GetString().c_str(), reason);
return NULL;
}
}
// Now all we can do is promote atomic types...
if (at0 == NULL || at1 == NULL) {
assert(reason != NULL);
Error(pos, "Implicit conversion from type \"%s\" to \"%s\" for %s not possible.",
t0->GetString().c_str(), t1->GetString().c_str(), reason);
return NULL;
}
// Finally, to determine which of the two atomic types is more general,
// use the ordering of entries in the AtomicType::BasicType enumerant.
// use the ordering of entries in the AtomicType::BasicType enumerator.
return (int(at0->basicType) >= int(at1->basicType)) ? at0 : at1;
}
bool
Type::Equal(const Type *a, const Type *b) {
if (!a || !b)
if (a == NULL || b == NULL)
return false;
// We can compare AtomicTypes with pointer equality, since the
// AtomicType constructor is private so that there isonly the single
// canonical instance of the AtomicTypes (AtomicType::UniformInt32,
// etc.)
if (dynamic_cast<const AtomicType *>(a) &&
dynamic_cast<const AtomicType *>(b))
if (dynamic_cast<const AtomicType *>(a) != NULL &&
dynamic_cast<const AtomicType *>(b) != NULL)
return a == b;
// For all of the other types, we need to see if we have the same two
// general types. If so, then we dig into the details of the type and
// see if all of the relevant bits are equal...
const EnumType *eta = dynamic_cast<const EnumType *>(a);
const EnumType *etb = dynamic_cast<const EnumType *>(b);
if (eta != NULL && etb != NULL)
// Kind of goofy, but this sufficies to check
return (eta->pos == etb->pos &&
eta->IsUniformType() == etb->IsUniformType() &&
eta->IsConstType() == etb->IsConstType());
const ArrayType *ata = dynamic_cast<const ArrayType *>(a);
const ArrayType *atb = dynamic_cast<const ArrayType *>(b);
if (ata && atb)
if (ata != NULL && atb != NULL)
return (ata->GetElementCount() == atb->GetElementCount() &&
Equal(ata->GetElementType(), atb->GetElementType()));
const VectorType *vta = dynamic_cast<const VectorType *>(a);
const VectorType *vtb = dynamic_cast<const VectorType *>(b);
if (vta && vtb)
if (vta != NULL && vtb != NULL)
return (vta->GetElementCount() == vtb->GetElementCount() &&
Equal(vta->GetElementType(), vtb->GetElementType()));
const StructType *sta = dynamic_cast<const StructType *>(a);
const StructType *stb = dynamic_cast<const StructType *>(b);
if (sta && stb) {
if (sta != NULL && stb != NULL) {
if (sta->GetElementCount() != stb->GetElementCount())
return false;
for (int i = 0; i < sta->GetElementCount(); ++i)
@@ -1793,13 +2052,13 @@ Type::Equal(const Type *a, const Type *b) {
const ReferenceType *rta = dynamic_cast<const ReferenceType *>(a);
const ReferenceType *rtb = dynamic_cast<const ReferenceType *>(b);
if (rta && rtb)
if (rta != NULL && rtb != NULL)
return Type::Equal(rta->GetReferenceTarget(),
rtb->GetReferenceTarget());
const FunctionType *fta = dynamic_cast<const FunctionType *>(a);
const FunctionType *ftb = dynamic_cast<const FunctionType *>(b);
if (fta && ftb) {
if (fta != NULL && ftb != NULL) {
// Both the return types and all of the argument types must match
// for function types to match
if (!Equal(fta->GetReturnType(), ftb->GetReturnType()))