Stop using dynamic_cast for Types.

We now have a set of template functions CastType<AtomicType>, etc., that in
turn use a new typeId field in each Type instance, allowing them to be inlined
and to be quite efficient.

This improves front-end performance for a particular large program by 28%.
This commit is contained in:
Matt Pharr
2012-05-04 11:12:33 -07:00
parent c756c855ea
commit 944c53bff1
11 changed files with 539 additions and 425 deletions

137
type.cpp
View File

@@ -184,7 +184,7 @@ const AtomicType *AtomicType::Void =
AtomicType::AtomicType(BasicType bt, Variability v, bool ic)
: basicType(bt), variability(v), isConst(ic) {
: Type(ATOMIC_TYPE), basicType(bt), variability(v), isConst(ic) {
}
@@ -532,7 +532,7 @@ AtomicType::GetDIType(llvm::DIDescriptor scope) const {
// EnumType
EnumType::EnumType(SourcePos p)
: pos(p) {
: Type(ENUM_TYPE), pos(p) {
// name = "/* (anonymous) */";
isConst = false;
variability = Variability(Variability::Unbound);
@@ -540,7 +540,7 @@ EnumType::EnumType(SourcePos p)
EnumType::EnumType(const char *n, SourcePos p)
: pos(p), name(n) {
: Type(ENUM_TYPE), pos(p), name(n) {
isConst = false;
variability = Variability(Variability::Unbound);
}
@@ -817,7 +817,7 @@ PointerType *PointerType::Void =
PointerType::PointerType(const Type *t, Variability v, bool ic, bool is,
bool fr)
: variability(v), isConst(ic), isSlice(is), isFrozen(fr) {
: Type(POINTER_TYPE), variability(v), isConst(ic), isSlice(is), isFrozen(fr) {
baseType = t;
}
@@ -1083,7 +1083,7 @@ PointerType::LLVMType(llvm::LLVMContext *ctx) const {
switch (variability.type) {
case Variability::Uniform: {
llvm::Type *ptype = NULL;
const FunctionType *ftype = dynamic_cast<const FunctionType *>(baseType);
const FunctionType *ftype = CastType<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
@@ -1155,7 +1155,7 @@ const Type *SequentialType::GetElementType(int index) const {
// ArrayType
ArrayType::ArrayType(const Type *c, int a)
: child(c), numElements(a) {
: SequentialType(ARRAY_TYPE), child(c), numElements(a) {
// 0 -> unsized array.
Assert(numElements >= 0);
Assert(Type::Equal(c, AtomicType::Void) == false);
@@ -1217,11 +1217,11 @@ ArrayType::IsConstType() const {
const Type *
ArrayType::GetBaseType() const {
const Type *type = child;
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
const ArrayType *at = CastType<ArrayType>(type);
// Keep walking until we reach a child that isn't itself an array
while (at) {
type = at->child;
at = dynamic_cast<const ArrayType *>(type);
at = CastType<ArrayType>(type);
}
return type;
}
@@ -1338,7 +1338,7 @@ ArrayType::GetString() const {
else
buf[0] = '\0';
s += std::string("[") + std::string(buf) + std::string("]");
at = dynamic_cast<const ArrayType *>(at->child);
at = CastType<ArrayType>(at->child);
}
return s;
}
@@ -1381,7 +1381,7 @@ ArrayType::GetCDeclaration(const std::string &name) const {
else
buf[0] = '\0';
s += std::string("[") + std::string(buf) + std::string("]");
at = dynamic_cast<const ArrayType *>(at->child);
at = CastType<ArrayType>(at->child);
}
if (soaWidth > 0) {
@@ -1396,7 +1396,7 @@ ArrayType::GetCDeclaration(const std::string &name) const {
int
ArrayType::TotalElementCount() const {
const ArrayType *ct = dynamic_cast<const ArrayType *>(child);
const ArrayType *ct = CastType<ArrayType>(child);
if (ct != NULL)
return numElements * ct->TotalElementCount();
else
@@ -1425,7 +1425,7 @@ ArrayType::GetSizedArray(int sz) const {
const Type *
ArrayType::SizeUnsizedArrays(const Type *type, Expr *initExpr) {
const ArrayType *at = dynamic_cast<const ArrayType *>(type);
const ArrayType *at = CastType<ArrayType>(type);
if (at == NULL)
return type;
@@ -1437,7 +1437,7 @@ ArrayType::SizeUnsizedArrays(const Type *type, Expr *initExpr) {
// length of the expression list
if (at->GetElementCount() == 0) {
type = at->GetSizedArray(exprList->exprs.size());
at = dynamic_cast<const ArrayType *>(type);
at = CastType<ArrayType>(type);
}
// Is there another nested level of expression lists? If not, bail out
@@ -1449,7 +1449,7 @@ ArrayType::SizeUnsizedArrays(const Type *type, Expr *initExpr) {
return type;
const Type *nextType = at->GetElementType();
const ArrayType *nextArrayType = dynamic_cast<const ArrayType *>(nextType);
const ArrayType *nextArrayType = CastType<ArrayType>(nextType);
if (nextArrayType != NULL && nextArrayType->GetElementCount() == 0) {
// If the recursive call to SizeUnsizedArrays at the bottom of the
// function is going to size an unsized dimension, make sure that
@@ -1485,7 +1485,7 @@ ArrayType::SizeUnsizedArrays(const Type *type, Expr *initExpr) {
// VectorType
VectorType::VectorType(const AtomicType *b, int a)
: base(b), numElements(a) {
: SequentialType(VECTOR_TYPE), base(b), numElements(a) {
Assert(numElements > 0);
Assert(base != NULL);
}
@@ -2111,8 +2111,7 @@ 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);
const StructType *childStructType = CastType<StructType>(eltType);
if (childStructType != NULL)
ok &= checkIfCanBeSOA(childStructType);
@@ -2124,7 +2123,7 @@ StructType::checkIfCanBeSOA(const StructType *st) {
eltType->IsUniformType() ? "uniform" : "varying");
ok = false;
}
else if (dynamic_cast<const ReferenceType *>(eltType)) {
else if (CastType<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());
@@ -2141,7 +2140,7 @@ StructType::checkIfCanBeSOA(const StructType *st) {
UndefinedStructType::UndefinedStructType(const std::string &n,
const Variability var, bool ic,
SourcePos p)
: name(n), variability(var), isConst(ic), pos(p) {
: Type(UNDEFINED_STRUCT_TYPE), name(n), variability(var), isConst(ic), pos(p) {
Assert(name != "");
if (variability != Variability::Unbound) {
// Create a new opaque LLVM struct type for this struct name
@@ -2303,7 +2302,7 @@ UndefinedStructType::GetDIType(llvm::DIDescriptor scope) const {
// ReferenceType
ReferenceType::ReferenceType(const Type *t)
: targetType(t) {
: Type(REFERENCE_TYPE), targetType(t) {
}
@@ -2493,7 +2492,7 @@ ReferenceType::GetCDeclaration(const std::string &name) const {
return "";
}
const ArrayType *at = dynamic_cast<const ArrayType *>(targetType);
const ArrayType *at = CastType<ArrayType>(targetType);
if (at != NULL) {
if (at->GetElementCount() == 0) {
// emit unsized arrays as pointers to the base type..
@@ -2553,8 +2552,8 @@ ReferenceType::GetDIType(llvm::DIDescriptor scope) const {
FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
SourcePos p)
: isTask(false), isExported(false), isExternC(false), returnType(r),
paramTypes(a), paramNames(std::vector<std::string>(a.size(), "")),
: Type(FUNCTION_TYPE), isTask(false), isExported(false), isExternC(false),
returnType(r), paramTypes(a), paramNames(std::vector<std::string>(a.size(), "")),
paramDefaults(std::vector<Expr *>(a.size(), NULL)),
paramPositions(std::vector<SourcePos>(a.size(), p)) {
Assert(returnType != NULL);
@@ -2568,8 +2567,8 @@ FunctionType::FunctionType(const Type *r, const std::vector<const Type *> &a,
const std::vector<Expr *> &ad,
const std::vector<SourcePos> &ap,
bool it, bool is, bool ec)
: isTask(it), isExported(is), isExternC(ec), returnType(r), paramTypes(a),
paramNames(an), paramDefaults(ad), paramPositions(ap) {
: Type(FUNCTION_TYPE), isTask(it), isExported(is), isExternC(ec), returnType(r),
paramTypes(a), paramNames(an), paramDefaults(ad), paramPositions(ap) {
Assert(paramTypes.size() == paramNames.size() &&
paramNames.size() == paramDefaults.size() &&
paramDefaults.size() == paramPositions.size());
@@ -2733,9 +2732,9 @@ FunctionType::GetCDeclaration(const std::string &fname) const {
// Convert pointers to arrays to unsized arrays, which are more clear
// to print out for multidimensional arrays (i.e. "float foo[][4] "
// versus "float (foo *)[4]").
const PointerType *pt = dynamic_cast<const PointerType *>(type);
const PointerType *pt = CastType<PointerType>(type);
if (pt != NULL &&
dynamic_cast<const ArrayType *>(pt->GetBaseType()) != NULL) {
CastType<ArrayType>(pt->GetBaseType()) != NULL) {
type = new ArrayType(pt->GetBaseType(), 0);
}
@@ -2906,7 +2905,7 @@ Type::GetAsUnsignedType() const {
*/
static const Type *
lVectorConvert(const Type *type, SourcePos pos, const char *reason, int vecSize) {
const VectorType *vt = dynamic_cast<const VectorType *>(type);
const VectorType *vt = CastType<VectorType>(type);
if (vt) {
if (vt->GetElementCount() != vecSize) {
Error(pos, "Implicit conversion between from vector type "
@@ -2917,7 +2916,7 @@ lVectorConvert(const Type *type, SourcePos pos, const char *reason, int vecSize)
return vt;
}
else {
const AtomicType *at = dynamic_cast<const AtomicType *>(type);
const AtomicType *at = CastType<AtomicType>(type);
if (!at) {
Error(pos, "Non-atomic type \"%s\" can't be converted to vector type "
"for %s.", type->GetString().c_str(), reason);
@@ -2935,11 +2934,10 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
// First, if one or both types are function types, convert them to
// pointer to function types and then try again.
if (dynamic_cast<const FunctionType *>(t0) ||
dynamic_cast<const FunctionType *>(t1)) {
if (dynamic_cast<const FunctionType *>(t0))
if (CastType<FunctionType>(t0) || CastType<FunctionType>(t1)) {
if (CastType<FunctionType>(t0))
t0 = PointerType::GetUniform(t0);
if (dynamic_cast<const FunctionType *>(t1))
if (CastType<FunctionType>(t1))
t1 = PointerType::GetUniform(t1);
return MoreGeneralType(t0, t1, pos, reason, forceVarying, vecSize);
}
@@ -2967,8 +2965,7 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
// If they're function types, it's hopeless if they didn't match in the
// Type::Equal() call above. Fail here so that we don't get into
// trouble calling GetAsConstType()...
if (dynamic_cast<const FunctionType *>(t0) ||
dynamic_cast<const FunctionType *>(t1)) {
if (CastType<FunctionType>(t0) || CastType<FunctionType>(t1)) {
Error(pos, "Incompatible function types \"%s\" and \"%s\" in %s.",
t0->GetString().c_str(), t1->GetString().c_str(), reason);
return NULL;
@@ -2979,8 +2976,8 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
if (Type::EqualIgnoringConst(t0, t1))
return t0->GetAsNonConstType();
const PointerType *pt0 = dynamic_cast<const PointerType *>(t0);
const PointerType *pt1 = dynamic_cast<const PointerType *>(t1);
const PointerType *pt0 = CastType<PointerType>(t0);
const PointerType *pt1 = CastType<PointerType>(t1);
if (pt0 != NULL && pt1 != NULL) {
if (PointerType::IsVoidPointer(pt0))
return pt1;
@@ -2994,8 +2991,8 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
}
}
const VectorType *vt0 = dynamic_cast<const VectorType *>(t0);
const VectorType *vt1 = dynamic_cast<const VectorType *>(t1);
const VectorType *vt0 = CastType<VectorType>(t0);
const VectorType *vt1 = CastType<VectorType>(t1);
if (vt0 && vt1) {
// both are vectors; convert their base types and make a new vector
// type, as long as their lengths match
@@ -3012,7 +3009,7 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
// The 'more general' version of the two vector element types must
// be an AtomicType (that's all that vectors can hold...)
const AtomicType *at = dynamic_cast<const AtomicType *>(t);
const AtomicType *at = CastType<AtomicType>(t);
Assert(at != NULL);
return new VectorType(at, vt0->GetElementCount());
@@ -3027,7 +3024,7 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
if (!t)
return NULL;
const AtomicType *at = dynamic_cast<const AtomicType *>(t);
const AtomicType *at = CastType<AtomicType>(t);
Assert(at != NULL);
return new VectorType(at, vt0->GetElementCount());
}
@@ -3039,18 +3036,18 @@ Type::MoreGeneralType(const Type *t0, const Type *t1, SourcePos pos, const char
if (!t)
return NULL;
const AtomicType *at = dynamic_cast<const AtomicType *>(t);
const AtomicType *at = CastType<AtomicType>(t);
Assert(at != NULL);
return new VectorType(at, vt1->GetElementCount());
}
// TODO: what do we need to do about references here, if anything??
const AtomicType *at0 = dynamic_cast<const AtomicType *>(t0->GetReferenceTarget());
const AtomicType *at1 = dynamic_cast<const AtomicType *>(t1->GetReferenceTarget());
const AtomicType *at0 = CastType<AtomicType>(t0->GetReferenceTarget());
const AtomicType *at1 = CastType<AtomicType>(t1->GetReferenceTarget());
const EnumType *et0 = dynamic_cast<const EnumType *>(t0->GetReferenceTarget());
const EnumType *et1 = dynamic_cast<const EnumType *>(t1->GetReferenceTarget());
const EnumType *et0 = CastType<EnumType>(t0->GetReferenceTarget());
const EnumType *et1 = CastType<EnumType>(t1->GetReferenceTarget());
if (et0 != NULL && et1 != NULL) {
// Two different enum types -> make them uint32s...
Assert(et0->IsVaryingType() == et1->IsVaryingType());
@@ -3098,9 +3095,9 @@ 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);
return (CastType<AtomicType>(type) != NULL ||
CastType<EnumType>(type) != NULL ||
CastType<PointerType>(type) != NULL);
}
@@ -3110,16 +3107,16 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
return false;
if (ignoreConst == true) {
if (dynamic_cast<const FunctionType *>(a) == NULL)
if (CastType<FunctionType>(a) == NULL)
a = a->GetAsNonConstType();
if (dynamic_cast<const FunctionType *>(b) == NULL)
if (CastType<FunctionType>(b) == NULL)
b = b->GetAsNonConstType();
}
else if (a->IsConstType() != b->IsConstType())
return false;
const AtomicType *ata = dynamic_cast<const AtomicType *>(a);
const AtomicType *atb = dynamic_cast<const AtomicType *>(b);
const AtomicType *ata = CastType<AtomicType>(a);
const AtomicType *atb = CastType<AtomicType>(b);
if (ata != NULL && atb != NULL) {
return ((ata->basicType == atb->basicType) &&
(ata->GetVariability() == atb->GetVariability()));
@@ -3128,33 +3125,31 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
// 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);
const EnumType *eta = CastType<EnumType>(a);
const EnumType *etb = CastType<EnumType>(b);
if (eta != NULL && etb != NULL)
// Kind of goofy, but this sufficies to check
return (eta->pos == etb->pos &&
eta->GetVariability() == etb->GetVariability());
const ArrayType *arta = dynamic_cast<const ArrayType *>(a);
const ArrayType *artb = dynamic_cast<const ArrayType *>(b);
const ArrayType *arta = CastType<ArrayType>(a);
const ArrayType *artb = CastType<ArrayType>(b);
if (arta != NULL && artb != NULL)
return (arta->GetElementCount() == artb->GetElementCount() &&
lCheckTypeEquality(arta->GetElementType(), artb->GetElementType(),
ignoreConst));
const VectorType *vta = dynamic_cast<const VectorType *>(a);
const VectorType *vtb = dynamic_cast<const VectorType *>(b);
const VectorType *vta = CastType<VectorType>(a);
const VectorType *vtb = CastType<VectorType>(b);
if (vta != NULL && vtb != NULL)
return (vta->GetElementCount() == vtb->GetElementCount() &&
lCheckTypeEquality(vta->GetElementType(), vtb->GetElementType(),
ignoreConst));
const StructType *sta = dynamic_cast<const StructType *>(a);
const StructType *stb = dynamic_cast<const StructType *>(b);
const UndefinedStructType *usta =
dynamic_cast<const UndefinedStructType *>(a);
const UndefinedStructType *ustb =
dynamic_cast<const UndefinedStructType *>(b);
const StructType *sta = CastType<StructType>(a);
const StructType *stb = CastType<StructType>(b);
const UndefinedStructType *usta = CastType<UndefinedStructType>(a);
const UndefinedStructType *ustb = CastType<UndefinedStructType>(b);
if ((sta != NULL || usta != NULL) && (stb != NULL || ustb != NULL)) {
// Report both defuned and undefined structs as equal if their
// names are the same.
@@ -3166,8 +3161,8 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
return (namea == nameb);
}
const PointerType *pta = dynamic_cast<const PointerType *>(a);
const PointerType *ptb = dynamic_cast<const PointerType *>(b);
const PointerType *pta = CastType<PointerType>(a);
const PointerType *ptb = CastType<PointerType>(b);
if (pta != NULL && ptb != NULL)
return (pta->IsUniformType() == ptb->IsUniformType() &&
pta->IsSlice() == ptb->IsSlice() &&
@@ -3175,14 +3170,14 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
lCheckTypeEquality(pta->GetBaseType(), ptb->GetBaseType(),
ignoreConst));
const ReferenceType *rta = dynamic_cast<const ReferenceType *>(a);
const ReferenceType *rtb = dynamic_cast<const ReferenceType *>(b);
const ReferenceType *rta = CastType<ReferenceType>(a);
const ReferenceType *rtb = CastType<ReferenceType>(b);
if (rta != NULL && rtb != NULL)
return (lCheckTypeEquality(rta->GetReferenceTarget(),
rtb->GetReferenceTarget(), ignoreConst));
const FunctionType *fta = dynamic_cast<const FunctionType *>(a);
const FunctionType *ftb = dynamic_cast<const FunctionType *>(b);
const FunctionType *fta = CastType<FunctionType>(a);
const FunctionType *ftb = CastType<FunctionType>(b);
if (fta != NULL && ftb != NULL) {
// Both the return types and all of the argument types must match
// for function types to match