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

View File

@@ -1564,8 +1564,9 @@ FunctionEmitContext::maskedStore(llvm::Value *rvalue, llvm::Value *lvalue,
return;
}
// We must have a regular atomic type at this point
assert(dynamic_cast<const AtomicType *>(rvalueType) != NULL);
// We must have a regular atomic or enumerator type at this point
assert(dynamic_cast<const AtomicType *>(rvalueType) != NULL ||
dynamic_cast<const EnumType *>(rvalueType) != NULL);
rvalueType = rvalueType->GetAsNonConstType();
llvm::Function *maskedStoreFunc = NULL;
@@ -1585,7 +1586,8 @@ FunctionEmitContext::maskedStore(llvm::Value *rvalue, llvm::Value *lvalue,
assert(rvalueType == AtomicType::VaryingFloat ||
rvalueType == AtomicType::VaryingBool ||
rvalueType == AtomicType::VaryingInt32 ||
rvalueType == AtomicType::VaryingUInt32);
rvalueType == AtomicType::VaryingUInt32 ||
dynamic_cast<const EnumType *>(rvalueType) != NULL);
maskedStoreFunc = m->module->getFunction("__pseudo_masked_store_32");
lvalue = BitCastInst(lvalue, LLVMTypes::Int32VectorPointerType,

View File

@@ -50,6 +50,7 @@ Contents:
+ `Lexical Structure`_
+ `Basic Types and Type Qualifiers`_
+ `Enumeration Types`_
+ `Short Vector Types`_
+ `Struct and Array Types`_
+ `Declarations and Initializers`_
@@ -550,6 +551,51 @@ results or modify existing variables.
``ispc`` doesn't currently support pointer types.
Enumeration Types
-----------------
It is possible to define user-defined enumeration types in ``ispc`` with
the ``enum`` keyword, which is followed by an option enumeration type name
and then a brace-delimited list of enumerators with optional values:
::
enum Color { RED, GREEN, BLUE };
enum Flags {
UNINITIALIZED = 0,
INITIALIZED = 2,
CACHED = 4
};
Each ``enum`` declaration defines a new type; an attempt to implicitly
convert between enumerations of different types gives a compile-time error,
but enuemrations of different types can be explicitly cast to one other.
::
Color c = (Color)CACHED;
Enumerators are implicitly converted to integer types, however, so they can
be directly passed to routines that take integer parameters and can be used
in expressions including integers, for example. However, the integer
result of such an expression must be explicitly cast back to the enumerant
type if it to be assigned to a variable with the enuemrant type.
::
Color c = RED;
int nextColor = c+1;
c = (Color)nextColor;
In this particular case, the explicit cast could be avoided using an
increment operator.
::
Color c = RED;
++c; // c == GREEN now
Short Vector Types
------------------
@@ -844,7 +890,6 @@ C Constructs not in ISPC
The following C features are not available in ``ispc``.
* ``enum`` s
* Pointers and function pointers
* ``char`` and ``short`` types
* ``switch`` statements

196
expr.cpp
View File

@@ -256,9 +256,33 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk) {
return new TypeCastExpr(toType, this, pos);
}
const EnumType *toEnumType = dynamic_cast<const EnumType *>(toType);
const EnumType *fromEnumType = dynamic_cast<const EnumType *>(fromType);
if (toEnumType != NULL && fromEnumType != NULL) {
// No implicit conversions between different enum types
if (!Type::Equal(toEnumType->GetAsUniformType()->GetAsConstType(),
fromEnumType->GetAsUniformType()->GetAsConstType())) {
if (!failureOk)
Error(pos, "Can't convert between different enum types "
"\"%s\" -> \"%s\".", fromEnumType->GetString().c_str(),
toEnumType->GetString().c_str());
return NULL;
}
return new TypeCastExpr(toType, this, pos);
}
const AtomicType *toAtomicType = dynamic_cast<const AtomicType *>(toType);
const AtomicType *fromAtomicType = dynamic_cast<const AtomicType *>(fromType);
// enum -> atomic (integer, generally...) is always ok
if (fromEnumType != NULL) {
assert(toAtomicType != NULL || toVectorType != NULL);
return new TypeCastExpr(toType, this, pos);
}
// from here on out, the from type can only be atomic something or
// other...
const AtomicType *fromAtomicType = dynamic_cast<const AtomicType *>(fromType);
if (fromAtomicType == NULL) {
if (!failureOk)
Error(pos, "Type conversion only possible from atomic types, not "
@@ -272,7 +296,6 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk) {
return new TypeCastExpr(toType, this, pos);
// ok, it better be a scalar->scalar conversion of some sort by now
const AtomicType *toAtomicType = dynamic_cast<const AtomicType *>(toType);
if (toAtomicType == NULL) {
if (!failureOk)
Error(pos, "Type conversion only possible to atomic types, not "
@@ -316,18 +339,22 @@ lMatchingBoolType(const Type *type) {
static llvm::Constant *
lLLVMConstantValue(const Type *type, llvm::LLVMContext *ctx, double value) {
const AtomicType *atomicType = dynamic_cast<const AtomicType *>(type);
const EnumType *enumType = dynamic_cast<const EnumType *>(type);
const VectorType *vectorType = dynamic_cast<const VectorType *>(type);
// This function is only called with, and only works for atomic and
// vector types.
assert(atomicType != NULL || vectorType != NULL);
// This function is only called with, and only works for atomic, enum,
// and vector types.
assert(atomicType != NULL || enumType != NULL || vectorType != NULL);
if (atomicType) {
// If it's an atomic type, then figure out which of the llvmutil.h
// functions to call to get the corresponding constant and then
// call it...
if (atomicType != NULL || enumType != NULL) {
// If it's an atomic or enuemrator type, then figure out which of
// the llvmutil.h functions to call to get the corresponding
// constant and then call it...
bool isUniform = type->IsUniformType();
switch (atomicType->basicType) {
AtomicType::BasicType basicType = (enumType != NULL) ?
AtomicType::TYPE_UINT32 : atomicType->basicType;
switch (basicType) {
case AtomicType::TYPE_VOID:
FATAL("can't get constant value for void type");
return NULL;
@@ -477,7 +504,7 @@ lEmitNegate(Expr *arg, SourcePos pos, FunctionEmitContext *ctx) {
return ctx->BinaryOperator(llvm::Instruction::FSub, zero, argVal, "fnegate");
else {
assert(type->IsIntType());
return ctx->BinaryOperator(llvm::Instruction::Sub, zero, argVal, "fnegate");
return ctx->BinaryOperator(llvm::Instruction::Sub, zero, argVal, "inegate");
}
}
@@ -561,6 +588,7 @@ UnaryExpr::Optimize() {
return this;
const Type *type = constExpr->GetType();
bool isEnumType = dynamic_cast<const EnumType *>(type) != NULL;
if (type == AtomicType::UniformInt64 ||
type == AtomicType::VaryingInt64 ||
@@ -607,7 +635,8 @@ UnaryExpr::Optimize() {
else if (type == AtomicType::UniformUInt32 ||
type == AtomicType::VaryingUInt32 ||
type == AtomicType::UniformConstUInt32 ||
type == AtomicType::VaryingConstUInt32) {
type == AtomicType::VaryingConstUInt32 ||
isEnumType == true) {
uint32_t v[ISPC_MAX_NVEC];
int count = constExpr->AsUInt32(v);
for (int i = 0; i < count; ++i)
@@ -1190,7 +1219,8 @@ BinaryExpr::Optimize() {
else
return this;
}
else if (type == AtomicType::UniformUInt32 || type == AtomicType::VaryingUInt32) {
else if (type == AtomicType::UniformUInt32 || type == AtomicType::VaryingUInt32 ||
dynamic_cast<const EnumType *>(type) != NULL) {
uint32_t v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->AsUInt32(v0);
constArg1->AsUInt32(v1);
@@ -2069,6 +2099,7 @@ FunctionCallExpr::tryResolve(bool (*matchFunc)(Expr *, const Type *)) {
assert(ft != NULL);
const std::vector<ConstExpr *> &argumentDefaults = ft->GetArgumentDefaults();
const std::vector<const Type *> &argTypes = ft->GetArgumentTypes();
assert(argumentDefaults.size() == argTypes.size());
for (unsigned int i = callArgs.size(); i < argTypes.size(); ++i) {
assert(argumentDefaults[i] != NULL);
args->exprs.push_back(argumentDefaults[i]);
@@ -3028,8 +3059,7 @@ MemberExpr::getCandidateNearMatches() const {
ConstExpr::ConstExpr(const Type *t, int32_t i, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstInt32);
int32Val[0] = i;
@@ -3038,8 +3068,7 @@ ConstExpr::ConstExpr(const Type *t, int32_t i, SourcePos p)
ConstExpr::ConstExpr(const Type *t, int32_t *i, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstInt32 ||
type == AtomicType::VaryingConstInt32);
@@ -3050,21 +3079,22 @@ ConstExpr::ConstExpr(const Type *t, int32_t *i, SourcePos p)
ConstExpr::ConstExpr(const Type *t, uint32_t u, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstUInt32);
assert(type == AtomicType::UniformConstUInt32 ||
(dynamic_cast<const EnumType *>(type) != NULL &&
type->IsUniformType()));
uint32Val[0] = u;
}
ConstExpr::ConstExpr(const Type *t, uint32_t *u, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstUInt32 ||
type == AtomicType::VaryingConstUInt32);
type == AtomicType::VaryingConstUInt32 ||
(dynamic_cast<const EnumType *>(type) != NULL));
for (int j = 0; j < Count(); ++j)
uint32Val[j] = u[j];
}
@@ -3072,8 +3102,7 @@ ConstExpr::ConstExpr(const Type *t, uint32_t *u, SourcePos p)
ConstExpr::ConstExpr(const Type *t, float f, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstFloat);
floatVal[0] = f;
@@ -3082,8 +3111,7 @@ ConstExpr::ConstExpr(const Type *t, float f, SourcePos p)
ConstExpr::ConstExpr(const Type *t, float *f, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstFloat ||
type == AtomicType::VaryingConstFloat);
@@ -3094,8 +3122,7 @@ ConstExpr::ConstExpr(const Type *t, float *f, SourcePos p)
ConstExpr::ConstExpr(const Type *t, int64_t i, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstInt64);
int64Val[0] = i;
@@ -3104,8 +3131,7 @@ ConstExpr::ConstExpr(const Type *t, int64_t i, SourcePos p)
ConstExpr::ConstExpr(const Type *t, int64_t *i, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstInt64 ||
type == AtomicType::VaryingConstInt64);
@@ -3116,8 +3142,7 @@ ConstExpr::ConstExpr(const Type *t, int64_t *i, SourcePos p)
ConstExpr::ConstExpr(const Type *t, uint64_t u, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformUInt64);
uint64Val[0] = u;
@@ -3126,8 +3151,7 @@ ConstExpr::ConstExpr(const Type *t, uint64_t u, SourcePos p)
ConstExpr::ConstExpr(const Type *t, uint64_t *u, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstUInt64 ||
type == AtomicType::VaryingConstUInt64);
@@ -3138,8 +3162,7 @@ ConstExpr::ConstExpr(const Type *t, uint64_t *u, SourcePos p)
ConstExpr::ConstExpr(const Type *t, double f, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstDouble);
doubleVal[0] = f;
@@ -3148,8 +3171,7 @@ ConstExpr::ConstExpr(const Type *t, double f, SourcePos p)
ConstExpr::ConstExpr(const Type *t, double *f, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstDouble ||
type == AtomicType::VaryingConstDouble);
@@ -3160,8 +3182,7 @@ ConstExpr::ConstExpr(const Type *t, double *f, SourcePos p)
ConstExpr::ConstExpr(const Type *t, bool b, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstBool);
boolVal[0] = b;
@@ -3170,8 +3191,7 @@ ConstExpr::ConstExpr(const Type *t, bool b, SourcePos p)
ConstExpr::ConstExpr(const Type *t, bool *b, SourcePos p)
: Expr(p) {
type = dynamic_cast<const AtomicType *>(t);
assert(type != NULL);
type = t;
type = type->GetAsConstType();
assert(type == AtomicType::UniformConstBool ||
type == AtomicType::VaryingConstBool);
@@ -3183,7 +3203,10 @@ ConstExpr::ConstExpr(const Type *t, bool *b, SourcePos p)
ConstExpr::ConstExpr(ConstExpr *old, double *v)
: Expr(old->pos) {
type = old->type;
switch (type->basicType) {
AtomicType::BasicType basicType = getBasicType();
switch (basicType) {
case AtomicType::TYPE_BOOL:
for (int i = 0; i < Count(); ++i)
boolVal[i] = (v[i] != 0.);
@@ -3215,6 +3238,18 @@ ConstExpr::ConstExpr(ConstExpr *old, double *v)
}
AtomicType::BasicType
ConstExpr::getBasicType() const {
const AtomicType *at = dynamic_cast<const AtomicType *>(type);
if (at != NULL)
return at->basicType;
else {
assert(dynamic_cast<const EnumType *>(type) != NULL);
return AtomicType::TYPE_UINT32;
}
}
const Type *
ConstExpr::GetType() const {
return type;
@@ -3226,10 +3261,9 @@ ConstExpr::GetValue(FunctionEmitContext *ctx) const {
ctx->SetDebugPos(pos);
bool isVarying = type->IsVaryingType();
// ConstExpr only represents atomic types; just dispatch out to the
// appropriate utility routine to get the llvm constant value of the
// type we need.
switch (type->basicType) {
AtomicType::BasicType basicType = getBasicType();
switch (basicType) {
case AtomicType::TYPE_BOOL:
if (isVarying)
return LLVMBoolVector(boolVal);
@@ -3314,7 +3348,7 @@ lConvert(const From *from, To *to, int count, bool forceVarying) {
int
ConstExpr::AsInt64(int64_t *ip, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, ip, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, ip, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, ip, Count(), forceVarying); break;
@@ -3331,7 +3365,7 @@ ConstExpr::AsInt64(int64_t *ip, bool forceVarying) const {
int
ConstExpr::AsUInt64(uint64_t *up, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, up, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, up, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, up, Count(), forceVarying); break;
@@ -3348,7 +3382,7 @@ ConstExpr::AsUInt64(uint64_t *up, bool forceVarying) const {
int
ConstExpr::AsDouble(double *d, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, d, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, d, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, d, Count(), forceVarying); break;
@@ -3365,7 +3399,7 @@ ConstExpr::AsDouble(double *d, bool forceVarying) const {
int
ConstExpr::AsFloat(float *fp, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, fp, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, fp, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, fp, Count(), forceVarying); break;
@@ -3382,7 +3416,7 @@ ConstExpr::AsFloat(float *fp, bool forceVarying) const {
int
ConstExpr::AsBool(bool *b, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, b, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, b, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, b, Count(), forceVarying); break;
@@ -3399,7 +3433,7 @@ ConstExpr::AsBool(bool *b, bool forceVarying) const {
int
ConstExpr::AsInt32(int32_t *ip, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, ip, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, ip, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, ip, Count(), forceVarying); break;
@@ -3416,7 +3450,7 @@ ConstExpr::AsInt32(int32_t *ip, bool forceVarying) const {
int
ConstExpr::AsUInt32(uint32_t *up, bool forceVarying) const {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, up, Count(), forceVarying); break;
case AtomicType::TYPE_INT32: lConvert(int32Val, up, Count(), forceVarying); break;
case AtomicType::TYPE_UINT32: lConvert(uint32Val, up, Count(), forceVarying); break;
@@ -3461,7 +3495,8 @@ ConstExpr::GetConstant(const Type *type) const {
else
return LLVMInt32Vector(iv);
}
else if (type == AtomicType::UniformUInt32 || type == AtomicType::VaryingUInt32) {
else if (type == AtomicType::UniformUInt32 || type == AtomicType::VaryingUInt32 ||
dynamic_cast<const EnumType *>(type) != NULL) {
uint32_t uiv[ISPC_MAX_NVEC];
AsUInt32(uiv, type->IsVaryingType());
if (type->IsUniformType())
@@ -3520,12 +3555,11 @@ ConstExpr::TypeCheck() {
}
void
ConstExpr::Print() const {
printf("[%s] (", GetType()->GetString().c_str());
for (int i = 0; i < Count(); ++i) {
switch (type->basicType) {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL:
printf("%s", boolVal[i] ? "true" : "false");
break;
@@ -4007,14 +4041,25 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
return cast;
}
const AtomicType *fromAtomic = dynamic_cast<const AtomicType *>(fromType);
// at this point, coming from an atomic type is all that's left...
assert(fromAtomic != NULL);
llvm::Value *exprVal = expr->GetValue(ctx);
if (!exprVal)
return NULL;
const EnumType *fromEnum = dynamic_cast<const EnumType *>(fromType);
const EnumType *toEnum = dynamic_cast<const EnumType *>(toType);
if (fromEnum)
// treat it as an uint32 type for the below and all will be good.
fromType = fromEnum->IsUniformType() ? AtomicType::UniformUInt32 :
AtomicType::VaryingUInt32;
if (toEnum)
// treat it as an uint32 type for the below and all will be good.
toType = toEnum->IsUniformType() ? AtomicType::UniformUInt32 :
AtomicType::VaryingUInt32;
const AtomicType *fromAtomic = dynamic_cast<const AtomicType *>(fromType);
// at this point, coming from an atomic type is all that's left...
assert(fromAtomic != NULL);
if (toVector) {
// scalar -> short vector conversion
llvm::Value *conv = lTypeConvAtomic(ctx, exprVal, toVector->GetElementType(),
@@ -4099,18 +4144,19 @@ TypeCastExpr::TypeCheck() {
return this;
}
else {
assert(dynamic_cast<const AtomicType *>(fromType) != NULL);
// If we're going from an atomic type, the only possible result is
// another atomic type
if (dynamic_cast<const AtomicType *>(toType) == NULL) {
Error(pos, "Can't convert from non-atomic type \"%s\" to \"%s\".",
assert(dynamic_cast<const AtomicType *>(fromType) != NULL ||
dynamic_cast<const EnumType *>(fromType) != NULL);
// If we're going from an atomic or enum type, the only possible
// result is another atomic or enum type
if (dynamic_cast<const AtomicType *>(toType) == NULL &&
dynamic_cast<const EnumType *>(toType) == NULL) {
Error(pos, "Can't convert from type \"%s\" to \"%s\".",
fromTypeString, toTypeString);
return NULL;
}
return this;
}
}
@@ -4128,10 +4174,11 @@ TypeCastExpr::Optimize() {
const Type *toType = GetType();
const AtomicType *toAtomic = dynamic_cast<const AtomicType *>(toType);
// If we're not casting to an atomic type, we can't do anything here,
// since ConstExprs can only represent atomic types. (So e.g. we're
// casting from an int to an int<4>.)
if (toAtomic == NULL)
const EnumType *toEnum = dynamic_cast<const EnumType *>(toType);
// If we're not casting to an atomic or enum type, we can't do anything
// here, since ConstExprs can only represent those two types. (So
// e.g. we're casting from an int to an int<4>.)
if (toAtomic == NULL && toEnum == NULL)
return this;
bool forceVarying = toType->IsVaryingType();
@@ -4139,7 +4186,9 @@ TypeCastExpr::Optimize() {
// All of the type conversion smarts we need is already in the
// ConstExpr::AsBool(), etc., methods, so we just need to call the
// appropriate one for the type that this cast is converting to.
switch (toAtomic->basicType) {
AtomicType::BasicType basicType = toAtomic ? toAtomic->basicType :
AtomicType::TYPE_UINT32;
switch (basicType) {
case AtomicType::TYPE_BOOL: {
bool bv[ISPC_MAX_NVEC];
constExpr->AsBool(bv, forceVarying);
@@ -4179,7 +4228,6 @@ TypeCastExpr::Optimize() {
FATAL("unimplemented");
}
return this;
}

11
expr.h
View File

@@ -39,6 +39,7 @@
#define ISPC_EXPR_H 1
#include "ispc.h"
#include "type.h"
class FunctionSymbolExpr;
@@ -318,9 +319,9 @@ private:
/** @brief Expression representing a compile-time constant value.
This class can currently represent compile-time constants of anything
that is an AtomicType; for anything more complex, we don't currently
have a representation of a compile-time constant that can be further
reasoned about.
that is an AtomicType or an EnumType; for anything more complex, we
don't currently have a representation of a compile-time constant that
can be further reasoned about.
*/
class ConstExpr : public Expr {
public:
@@ -412,7 +413,9 @@ public:
int Count() const;
private:
const AtomicType *type;
AtomicType::BasicType getBasicType() const;
const Type *type;
union {
int32_t int32Val[ISPC_MAX_NVEC];
uint32_t uint32Val[ISPC_MAX_NVEC];

View File

@@ -135,3 +135,14 @@ SourcePos::Print() const {
printf(" @ [%s:%d.%d - %d.%d] ", name, first_line, first_column,
last_line, last_column);
}
bool
SourcePos::operator==(const SourcePos &p2) const {
return (!strcmp(name, p2.name) &&
first_line == p2.first_line &&
first_column == p2.first_column &&
last_line == p2.last_line &&
last_column == p2.last_column);
}

4
ispc.h
View File

@@ -117,6 +117,8 @@ struct SourcePos {
/** Returns a LLVM DIFile object that represents the SourcePos's file */
llvm::DIFile GetDIFile() const;
bool operator==(const SourcePos &p2) const;
};
@@ -156,7 +158,7 @@ public:
struct Target {
Target();
/** Enumerant giving the instruction sets that the compiler can
/** Enumerator giving the instruction sets that the compiler can
target. */
enum ISA { SSE2, SSE4, AVX };

3
lex.ll
View File

@@ -35,10 +35,11 @@
#include "ispc.h"
#include "decl.h"
#include "parse.hh"
#include "sym.h"
#include "util.h"
#include "module.h"
#include "type.h"
#include "parse.hh"
#include <stdlib.h>
static uint64_t lParseBinary(const char *ptr, SourcePos pos);

View File

@@ -1005,26 +1005,6 @@ Module::writeObjectFileOrAssembly(OutputType outputType, const char *outFileName
}
/** Walk through the elements of the given structure; for any elements that
are themselves structs, add their Type * to structParamTypes and
recursively process their elements.
*/
static void
lRecursiveAddStructs(const StructType *structType,
std::vector<const StructType *> &structParamTypes) {
for (int i = 0; i < structType->GetElementCount(); ++i) {
const Type *elementBaseType = structType->GetElementType(i)->GetBaseType();
const StructType *elementStructType =
dynamic_cast<const StructType *>(elementBaseType);
if (elementStructType != NULL) {
structParamTypes.push_back(elementStructType);
lRecursiveAddStructs(elementStructType, structParamTypes);
}
}
}
/** Small structure used in representing dependency graphs of structures
(i.e. given a StructType, which other structure types does it have as
elements).
@@ -1125,6 +1105,42 @@ lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file) {
}
/** Emit C declarations of enumerator types to the generated header file.
*/
static void
lEmitEnumDecls(const std::vector<const EnumType *> &enumTypes, FILE *file) {
if (enumTypes.size() == 0)
return;
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
fprintf(file, "// Enumerator types with external visibility from ispc code\n");
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n\n");
for (unsigned int i = 0; i < enumTypes.size(); ++i) {
std::string declaration = enumTypes[i]->GetCDeclaration("");
fprintf(file, "%s {\n", declaration.c_str());
// Print the individual enumerators
for (int j = 0; j < enumTypes[i]->GetEnumeratorCount(); ++j) {
const Symbol *e = enumTypes[i]->GetEnumerator(j);
assert(e->constValue != NULL);
unsigned int enumValue;
int count = e->constValue->AsUInt32(&enumValue);
assert(count == 1);
// Always print an initializer to set the value. We could be
// 'clever' here and detect whether the implicit value given by
// one plus the previous enumerator value (or zero, for the
// first enumerator) is the same as the value stored with the
// enumerator, though that doesn't seem worth the trouble...
fprintf(file, " %s = %d%c\n", e->name.c_str(), enumValue,
(j < enumTypes[i]->GetEnumeratorCount() - 1) ? ',' : ' ');
}
fprintf(file, "};\n");
}
}
/** Print declarations of VectorTypes used in 'export'ed parts of the
program in the header file.
*/
@@ -1137,7 +1153,6 @@ lEmitVectorTypedefs(const std::vector<const VectorType *> &types, FILE *file) {
fprintf(file, "// Vector types with external visibility from ispc code\n");
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n\n");
std::vector<const VectorType *> emittedTypes;
int align = g->target.nativeVectorWidth * 4;
for (unsigned int i = 0; i < types.size(); ++i) {
@@ -1145,17 +1160,6 @@ lEmitVectorTypedefs(const std::vector<const VectorType *> &types, FILE *file) {
const VectorType *vt = types[i]->GetAsNonConstType();
int size = vt->GetElementCount();
// Don't print the declaration for this type if we've already
// handled it.
//
// FIXME: this is n^2, unnecessarily. Being able to compare Type
// *s directly will eventually make this much better--can use a
// std::set... Probably not going to matter in practice.
for (unsigned int j = 0; j < emittedTypes.size(); ++j) {
if (Type::Equal(vt, emittedTypes[j]))
goto skip;
}
baseDecl = vt->GetBaseType()->GetCDeclaration("");
fprintf(file, "#ifdef _MSC_VER\n__declspec( align(%d) ) ", align);
fprintf(file, "struct %s%d { %s v[%d]; };\n", baseDecl.c_str(), size,
@@ -1164,58 +1168,59 @@ lEmitVectorTypedefs(const std::vector<const VectorType *> &types, FILE *file) {
fprintf(file, "struct %s%d { %s v[%d]; } __attribute__ ((aligned(%d)));\n",
baseDecl.c_str(), size, baseDecl.c_str(), size, align);
fprintf(file, "#endif\n");
emittedTypes.push_back(vt);
skip:
;
}
fprintf(file, "\n");
}
/** Given a set of StructTypes, walk through their elements and collect the
VectorTypes that are present in them.
/** Add the given type to the vector, if that type isn't already in there.
*/
static void
lGetVectorsFromStructs(const std::vector<const StructType *> &structParamTypes,
std::vector<const VectorType *> *vectorParamTypes) {
for (unsigned int i = 0; i < structParamTypes.size(); ++i) {
const StructType *structType = structParamTypes[i];
for (int j = 0; j < structType->GetElementCount(); ++j) {
const Type *elementType = structType->GetElementType(j);
template <typename T> static void
lAddTypeIfNew(const Type *type, std::vector<const T *> *exportedTypes) {
type = type->GetAsNonConstType();
const ArrayType *at = dynamic_cast<const ArrayType *>(elementType);
if (at)
elementType = at->GetBaseType();
// Linear search, so this ends up being n^2. It's unlikely this will
// matter in practice, though.
for (unsigned int i = 0; i < exportedTypes->size(); ++i)
if (Type::Equal((*exportedTypes)[i], type))
return;
const VectorType *vt = dynamic_cast<const VectorType *>(elementType);
if (vt != NULL) {
// make sure it isn't there already...
for (unsigned int k = 0; k < vectorParamTypes->size(); ++k)
if (Type::Equal(vt, (*vectorParamTypes)[k]))
goto skip;
vectorParamTypes->push_back(vt);
}
skip:
;
}
}
const T *castType = dynamic_cast<const T *>(type);
assert(castType != NULL);
exportedTypes->push_back(castType);
}
/** Given an arbitrary type that appears in the app/ispc interface, add it
to an appropriate vector if it is a struct, enum, or short vector type.
Then, if it's a struct, recursively process its members to do the same.
*/
static void
lGetStructAndVectorTypes(const Type *type,
std::vector<const StructType *> *structParamTypes,
std::vector<const VectorType *> *vectorParamTypes) {
const StructType *st = dynamic_cast<const StructType *>(type->GetBaseType());
if (st != NULL)
structParamTypes->push_back(st);
const VectorType *vt = dynamic_cast<const VectorType *>(type);
if (vt != NULL)
vectorParamTypes->push_back(vt);
vt = dynamic_cast<const VectorType *>(type->GetBaseType());
if (vt != NULL)
vectorParamTypes->push_back(vt);
lGetExportedTypes(const Type *type,
std::vector<const StructType *> *exportedStructTypes,
std::vector<const EnumType *> *exportedEnumTypes,
std::vector<const VectorType *> *exportedVectorTypes) {
const ArrayType *arrayType = dynamic_cast<const ArrayType *>(type);
const StructType *structType = dynamic_cast<const StructType *>(type);
if (dynamic_cast<const ReferenceType *>(type) != NULL)
lGetExportedTypes(type->GetReferenceTarget(), exportedStructTypes,
exportedEnumTypes, exportedVectorTypes);
else if (arrayType != NULL)
lGetExportedTypes(arrayType->GetElementType(), exportedStructTypes,
exportedEnumTypes, exportedVectorTypes);
else if (structType != NULL) {
lAddTypeIfNew(type, exportedStructTypes);
for (int i = 0; i < structType->GetElementCount(); ++i)
lGetExportedTypes(structType->GetElementType(i), exportedStructTypes,
exportedEnumTypes, exportedVectorTypes);
}
else if (dynamic_cast<const EnumType *>(type) != NULL)
lAddTypeIfNew(type, exportedEnumTypes);
else if (dynamic_cast<const VectorType *>(type) != NULL)
lAddTypeIfNew(type, exportedVectorTypes);
else
assert(dynamic_cast<const AtomicType *>(type) != NULL);
}
@@ -1223,18 +1228,21 @@ lGetStructAndVectorTypes(const Type *type,
present in the parameters to them.
*/
static void
lGetStructAndVectorParams(const std::vector<Symbol *> &funcs,
std::vector<const StructType *> *structParamTypes,
std::vector<const VectorType *> *vectorParamTypes) {
lGetExportedParamTypes(const std::vector<Symbol *> &funcs,
std::vector<const StructType *> *exportedStructTypes,
std::vector<const EnumType *> *exportedEnumTypes,
std::vector<const VectorType *> *exportedVectorTypes) {
for (unsigned int i = 0; i < funcs.size(); ++i) {
const FunctionType *ftype = dynamic_cast<const FunctionType *>(funcs[i]->type);
lGetStructAndVectorTypes(ftype->GetReturnType(), structParamTypes,
vectorParamTypes);
// Handle the return type
lGetExportedTypes(ftype->GetReturnType(), exportedStructTypes,
exportedEnumTypes, exportedVectorTypes);
// And now the parameter types...
const std::vector<const Type *> &argTypes = ftype->GetArgumentTypes();
for (unsigned int j = 0; j < argTypes.size(); ++j) {
lGetStructAndVectorTypes(argTypes[j], structParamTypes,
vectorParamTypes);
}
for (unsigned int j = 0; j < argTypes.size(); ++j)
lGetExportedTypes(argTypes[j], exportedStructTypes,
exportedEnumTypes, exportedVectorTypes);
}
}
@@ -1323,42 +1331,25 @@ Module::writeHeader(const char *fn) {
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
// Get all of the structs used as function parameters and extern
// globals. These vectors may have repeats.
std::vector<const StructType *> structParamTypes;
std::vector<const VectorType *> vectorParamTypes;
lGetStructAndVectorParams(exportedFuncs, &structParamTypes, &vectorParamTypes);
lGetStructAndVectorParams(externCFuncs, &structParamTypes, &vectorParamTypes);
// Get all of the struct, vector, and enumerant types used as function
// parameters. These vectors may have repeats.
std::vector<const StructType *> exportedStructTypes;
std::vector<const EnumType *> exportedEnumTypes;
std::vector<const VectorType *> exportedVectorTypes;
lGetExportedParamTypes(exportedFuncs, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes);
lGetExportedParamTypes(externCFuncs, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes);
// And do same for the 'extern' globals
// And do the same for the 'extern' globals
for (unsigned int i = 0; i < externGlobals.size(); ++i)
lGetStructAndVectorTypes(externGlobals[i]->type,
&structParamTypes, &vectorParamTypes);
lGetExportedTypes(externGlobals[i]->type, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes);
// Get all of the structs that the structs we have seen so far they
// depend on transitively. Note the array may grow as a result of the
// call to lRecursiveAddStructs -> an iterator would be a bad idea
// (would be invalidated) -> the value of size() may increase as we go
// along. But that's good; that lets us actually get the whole
// transitive set of struct types we need.
for (unsigned int i = 0; i < structParamTypes.size(); ++i)
lRecursiveAddStructs(structParamTypes[i], structParamTypes);
// Now get the unique struct types. This is an n^2 search, which is
// kind of ugly, but unlikely to be a problem in practice.
std::vector<const StructType *> uniqueStructTypes;
for (unsigned int i = 0; i < structParamTypes.size(); ++i) {
for (unsigned int j = 0; j < uniqueStructTypes.size(); ++j)
if (Type::Equal(structParamTypes[i], uniqueStructTypes[j]))
goto skip;
uniqueStructTypes.push_back(structParamTypes[i]);
skip:
;
}
lGetVectorsFromStructs(uniqueStructTypes, &vectorParamTypes);
lEmitVectorTypedefs(vectorParamTypes, f);
lEmitStructDecls(uniqueStructTypes, f);
// And print them
lEmitVectorTypedefs(exportedVectorTypes, f);
lEmitEnumDecls(exportedEnumTypes, f);
lEmitStructDecls(exportedStructTypes, f);
// emit externs for globals
if (externGlobals.size() > 0) {
@@ -1396,6 +1387,7 @@ Module::writeHeader(const char *fn) {
return true;
}
void
Module::execPreprocessor(const char* infilename, llvm::raw_string_ostream* ostream) const
{

214
parse.yy
View File

@@ -94,6 +94,9 @@ static void lAddMaskToSymbolTable(SourcePos pos);
static void lAddThreadIndexCountToSymbolTable(SourcePos pos);
static std::string lGetAlternates(std::vector<std::string> &alternates);
static const char *lGetStorageClassString(StorageClass sc);
static bool lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage);
static void lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
const EnumType *enumType);
static const char *lBuiltinTokens[] = {
"bool", "break", "case", "cbreak", "ccontinue", "cdo", "cfor", "char",
@@ -128,6 +131,9 @@ static const char *lParamListTokens[] = {
std::vector<Declarator *> *structDeclaratorList;
StructDeclaration *structDeclaration;
std::vector<StructDeclaration *> *structDeclarationList;
const EnumType *enumType;
Symbol *enumerator;
std::vector<Symbol *> *enumeratorList;
int32_t int32Val;
double floatVal;
int64_t int64Val;
@@ -180,8 +186,12 @@ static const char *lParamListTokens[] = {
%type <structDeclaration> struct_declaration
%type <structDeclarationList> struct_declaration_list
%type <enumeratorList> enumerator_list
%type <enumerator> enumerator
%type <enumType> enum_specifier
%type <type> specifier_qualifier_list struct_or_union_specifier
%type <type> enum_specifier type_specifier type_name
%type <type> type_specifier type_name
%type <type> short_vec_specifier
%type <atomicType> atomic_var_type_specifier
@@ -190,7 +200,7 @@ static const char *lParamListTokens[] = {
%type <declSpecs> declaration_specifiers
%type <stringVal> string_constant
%type <constCharPtr> struct_or_union_name
%type <constCharPtr> struct_or_union_name enum_identifier
%type <int32Val> int_constant soa_width_specifier
%start translation_unit
@@ -571,11 +581,7 @@ type_specifier
$$ = t;
}
| struct_or_union_specifier { $$ = $1; }
| enum_specifier
{ UNIMPLEMENTED; }
/* | TOKEN_TYPE_NAME
{ UNIMPLEMENTED; }
*/
| enum_specifier { $$ = $1; }
;
atomic_var_type_specifier
@@ -641,7 +647,8 @@ struct_or_union_specifier
Error(@2, "Struct type \"%s\" unknown.%s", $2, alts.c_str());
}
else if (dynamic_cast<const StructType *>(st) == NULL)
Error(@2, "Type \"%s\" is not a struct type!", $2);
Error(@2, "Type \"%s\" is not a struct type! (%s)", $2,
st->GetString().c_str());
$$ = st;
}
;
@@ -734,24 +741,98 @@ struct_declarator
*/
;
enum_identifier
: TOKEN_IDENTIFIER { $$ = strdup(yytext); }
enum_specifier
: TOKEN_ENUM '{' enumerator_list '}'
{ UNIMPLEMENTED; }
| TOKEN_ENUM TOKEN_IDENTIFIER '{' enumerator_list '}'
{ UNIMPLEMENTED; }
| TOKEN_ENUM TOKEN_IDENTIFIER
{ UNIMPLEMENTED; }
{
if ($3 != NULL) {
EnumType *enumType = new EnumType(@1);
lFinalizeEnumeratorSymbols(*$3, enumType);
for (unsigned int i = 0; i < $3->size(); ++i)
m->symbolTable->AddVariable((*$3)[i]);
enumType->SetEnumerators(*$3);
$$ = enumType;
}
else
$$ = NULL;
}
| TOKEN_ENUM enum_identifier '{' enumerator_list '}'
{
if ($4 != NULL) {
EnumType *enumType = new EnumType($2, $2);
m->symbolTable->AddType($2, enumType, @2);
lFinalizeEnumeratorSymbols(*$4, enumType);
for (unsigned int i = 0; i < $4->size(); ++i)
m->symbolTable->AddVariable((*$4)[i]);
enumType->SetEnumerators(*$4);
$$ = enumType;
}
else
$$ = NULL;
}
| TOKEN_ENUM enum_identifier
{
const Type *type = m->symbolTable->LookupType($2);
if (type == NULL) {
std::vector<std::string> alternates = m->symbolTable->ClosestEnumTypeMatch($2);
std::string alts = lGetAlternates(alternates);
Error(@2, "Enum type \"%s\" unknown.%s", $2, alts.c_str());
$$ = NULL;
}
else {
const EnumType *enumType = dynamic_cast<const EnumType *>(type);
if (enumType == NULL) {
Error(@2, "Type \"%s\" is not an enum type (%s).", $2,
type->GetString().c_str());
$$ = NULL;
}
else
$$ = enumType;
}
}
;
enumerator_list
: enumerator
{ UNIMPLEMENTED; }
{
if ($1 == NULL)
$$ = NULL;
else {
std::vector<Symbol *> *el = new std::vector<Symbol *>;
el->push_back($1);
$$ = el;
}
}
| enumerator_list ',' enumerator
{
if ($1 != NULL && $3 != NULL)
$1->push_back($3);
$$ = $1;
}
;
enumerator
: TOKEN_IDENTIFIER
| TOKEN_IDENTIFIER '=' constant_expression
: enum_identifier
{
$$ = new Symbol($1, @1);
}
| enum_identifier '=' constant_expression
{
int value;
if ($1 != NULL && $3 != NULL &&
lGetConstantInt($3, &value, @3, "Enumerator value")) {
Symbol *sym = new Symbol($1, @1);
sym->constValue = new ConstExpr(AtomicType::UniformConstUInt32,
(uint32_t)value, @3);
$$ = sym;
}
else
$$ = NULL;
}
;
type_qualifier
@@ -781,25 +862,10 @@ direct_declarator
| '(' declarator ')' { $$ = $2; }
| direct_declarator '[' constant_expression ']'
{
Expr *size = $3;
if (size)
size = size->TypeCheck();
if (size && $1 != NULL) {
size = size->Optimize();
llvm::Constant *cval = size->GetConstant(size->GetType());
if (!cval) {
Error(@3, "Array dimension must be compile-time constant");
$$ = NULL;
}
else {
llvm::ConstantInt *ci = llvm::dyn_cast<llvm::ConstantInt>(cval);
if (!ci) {
Error(@3, "Array dimension must be compile-time integer constant.");
$$ = NULL;
}
$1->AddArrayDimension((int)ci->getZExtValue());
$$ = $1;
}
int size;
if ($1 != NULL && lGetConstantInt($3, &size, @3, "Array dimension")) {
$1->AddArrayDimension(size);
$$ = $1;
}
else
$$ = NULL;
@@ -1238,3 +1304,81 @@ lGetStorageClassString(StorageClass sc) {
}
/** Given an expression, see if it is equal to a compile-time constant
integer value. If so, return true and return the value in *value.
If the expression isn't a compile-time constant or isn't an integer
type, return false.
*/
static bool
lGetConstantInt(Expr *expr, int *value, SourcePos pos, const char *usage) {
if (expr == NULL)
return false;
expr = expr->TypeCheck();
if (expr == NULL)
return false;
expr = expr->Optimize();
if (expr == NULL)
return false;
llvm::Constant *cval = expr->GetConstant(expr->GetType());
if (cval == NULL) {
Error(pos, "%s must be a compile-time constant.", usage);
return false;
}
else {
llvm::ConstantInt *ci = llvm::dyn_cast<llvm::ConstantInt>(cval);
if (ci == NULL) {
Error(pos, "%s must be a compile-time integer constant.", usage);
return false;
}
*value = (int)ci->getZExtValue();
return true;
}
}
/** Given an array of enumerator symbols, make sure each of them has a
ConstExpr * in their Symbol::constValue member that stores their
unsigned integer value. Symbols that had values explicitly provided
in the source file will already have ConstExpr * set; we just need
to set the values for the others here.
*/
static void
lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
const EnumType *enumType) {
enumType = enumType->GetAsConstType();
enumType = enumType->GetAsUniformType();
/* nextVal tracks the value for the next enumerant. It starts from
zero and goes up with each successive enumerant. If any of them
has a value specified, then nextVal is ignored for that one and is
set to one plus that one's value for the default value for the next
one. */
uint32_t nextVal = 0;
for (unsigned int i = 0; i < enums.size(); ++i) {
enums[i]->type = enumType;
if (enums[i]->constValue != NULL) {
/* Already has a value, so first update nextVal with it. */
int count = enums[i]->constValue->AsUInt32(&nextVal);
assert(count == 1);
++nextVal;
/* When the source file as being parsed, the ConstExpr for any
enumerant with a specified value was set to have unsigned
int32 type, since we haven't created the parent EnumType
by then. Therefore, add a little type cast from uint32 to
the actual enum type here and optimize it, which will have
us end up with a ConstExpr with the desired EnumType... */
Expr *castExpr = new TypeCastExpr(enumType, enums[i]->constValue,
enums[i]->pos);
castExpr = castExpr->Optimize();
enums[i]->constValue = dynamic_cast<ConstExpr *>(castExpr);
assert(enums[i]->constValue != NULL);
}
else {
enums[i]->constValue = new ConstExpr(enumType, nextVal++,
enums[i]->pos);
}
}
}

View File

@@ -152,13 +152,14 @@ lInitSymbol(llvm::Value *lvalue, const char *symName, const Type *type,
}
}
// Atomic types can't be initialized with { ... } initializer
// Atomic types and enums can't be initialized with { ... } initializer
// expressions, so print an error and return if that's what we've got
// here..
if (dynamic_cast<const AtomicType *>(type) != NULL) {
if (dynamic_cast<const AtomicType *>(type) != NULL ||
dynamic_cast<const EnumType *>(type) != NULL) {
if (dynamic_cast<ExprList *>(initExpr) != NULL)
Error(initExpr->pos, "Expression list initializers can't be used for "
"variable \"%s\' with atomic type \"%s\".", symName,
"variable \"%s\' with type \"%s\".", symName,
type->GetString().c_str());
return;
}
@@ -373,7 +374,8 @@ DeclStmt::TypeCheck() {
// the int->float type conversion is in there and we don't return
// an int as the constValue later...
const Type *type = decl->sym->type;
if (dynamic_cast<const AtomicType *>(type) != NULL) {
if (dynamic_cast<const AtomicType *>(type) != NULL ||
dynamic_cast<const EnumType *>(type) != NULL) {
// If it's an expr list with an atomic type, we'll later issue
// an error. Need to leave decl->initExpr as is in that case so it
// is in fact caught later, though.

23
sym.cpp
View File

@@ -59,6 +59,7 @@ Symbol::MangledName() const {
return name + type->Mangle();
}
///////////////////////////////////////////////////////////////////////////
// SymbolTable
@@ -257,7 +258,19 @@ SymbolTable::ClosestVariableOrFunctionMatch(const char *str) const {
std::vector<std::string>
SymbolTable::ClosestTypeMatch(const char *str) const {
// This follows the same approach as ClosestVariableOrFunctionmatch()
return closestTypeMatch(str, true);
}
std::vector<std::string>
SymbolTable::ClosestEnumTypeMatch(const char *str) const {
return closestTypeMatch(str, false);
}
std::vector<std::string>
SymbolTable::closestTypeMatch(const char *str, bool structsVsEnums) const {
// This follows the same approach as ClosestVariableOrFunctionMatch()
// above; compute all edit distances, keep the ones shorter than
// maxDelta, return the first non-empty vector of one or more sets of
// alternatives with minimal edit distance.
@@ -267,6 +280,14 @@ SymbolTable::ClosestTypeMatch(const char *str) const {
for (unsigned int i = 0; i < types.size(); ++i) {
TypeMapType::const_iterator iter;
for (iter = types[i]->begin(); iter != types[i]->end(); ++iter) {
// Skip over either StructTypes or EnumTypes, depending on the
// value of the structsVsEnums parameter
bool isEnum = (dynamic_cast<const EnumType *>(iter->second) != NULL);
if (isEnum && structsVsEnums)
continue;
else if (!isEnum && !structsVsEnums)
continue;
int dist = StringEditDistance(str, iter->first, maxDelta+1);
if (dist <= maxDelta)
matches[dist].push_back(iter->first);

5
sym.h
View File

@@ -219,11 +219,16 @@ public:
name. */
std::vector<std::string> ClosestTypeMatch(const char *name) const;
std::vector<std::string> ClosestEnumTypeMatch(const char *name) const;
/** Prints out the entire contents of the symbol table to standard error.
(Debugging method). */
void Print();
private:
std::vector<std::string> closestTypeMatch(const char *str,
bool structsVsEnums) const;
/** This member variable holds one \c vector of Symbol pointers for
each of the current active scopes as the program is being parsed.
New vectors of symbols are added and removed from the end of the

16
tests/enum-1.ispc Normal file
View File

@@ -0,0 +1,16 @@
enum Foo {
ZERO,
ONE,
TWO
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
RET[programIndex] = ONE;
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

18
tests/enum-2.ispc Normal file
View File

@@ -0,0 +1,18 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
RET[programIndex] = TEN;
}
export void result(uniform float RET[]) {
RET[programIndex] = 10;
}

18
tests/enum-3.ispc Normal file
View File

@@ -0,0 +1,18 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
RET[programIndex] = ELEVEN;
}
export void result(uniform float RET[]) {
RET[programIndex] = 11;
}

26
tests/enum-4.ispc Normal file
View File

@@ -0,0 +1,26 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
enum Bar {
FIFTY = 50,
THOUSAND = 1000
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex];
Foo foo = (Foo)((a == 1.) ? ELEVEN : FIFTY);
RET[programIndex] = (int)foo;
}
export void result(uniform float RET[]) {
RET[programIndex] = 50;
RET[0] = 11;
}

26
tests/enum-5.ispc Normal file
View File

@@ -0,0 +1,26 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
enum Bar {
FIFTY = 50,
THOUSAND = 1000
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex];
uniform Foo f = ONE;
int g = ++f;
RET[programIndex] = g-1;
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

26
tests/enum-6.ispc Normal file
View File

@@ -0,0 +1,26 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
enum Bar {
FIFTY = 50,
THOUSAND = 1000
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex];
uniform Foo f = ONE;
++f;
RET[programIndex] = (int)f;
}
export void result(uniform float RET[]) {
RET[programIndex] = 2;
}

27
tests/enum-7.ispc Normal file
View File

@@ -0,0 +1,27 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
enum Bar {
FIFTY = 50,
THOUSAND = 1000
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex];
uniform Foo f = ONE;
Foo vf = f;
++vf;
RET[programIndex] = (int)vf;
}
export void result(uniform float RET[]) {
RET[programIndex] = 2;
}

26
tests/enum-8.ispc Normal file
View File

@@ -0,0 +1,26 @@
enum Foo {
ZERO,
ONE,
TWO,
TEN = 10,
ELEVEN
};
enum Bar {
FIFTY = 50,
THOUSAND = 1000
};
export uniform int width() { return programCount; }
Foo Func(Foo f) { return ++f; }
Bar Func(Bar b) { return FIFTY; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
RET[programIndex] = (int)Func(ONE);
}
export void result(uniform float RET[]) {
RET[programIndex] = 2;
}

16
tests/enum-9.ispc Normal file
View File

@@ -0,0 +1,16 @@
enum {
ZERO,
ONE,
TWO
};
export uniform int width() { return programCount; }
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
RET[programIndex] = ONE;
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}

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()))

48
type.h
View File

@@ -205,7 +205,7 @@ public:
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
/** This enumerant records the basic types that AtomicTypes can be
/** This enumerator records the basic types that AtomicTypes can be
built from. */
enum BasicType {
TYPE_VOID,
@@ -243,6 +243,52 @@ private:
};
/** @brief Type implementation for enumerated types
*/
class EnumType : public Type {
public:
/** Constructor for anonymous enumerated types */
EnumType(SourcePos pos);
/** Constructor for named enumerated types */
EnumType(const char *name, SourcePos pos);
bool IsUniformType() const;
bool IsBoolType() const;
bool IsFloatType() const;
bool IsIntType() const;
bool IsUnsignedType() const;
bool IsConstType() const;
const EnumType *GetBaseType() const;
const EnumType *GetAsVaryingType() const;
const EnumType *GetAsUniformType() const;
const Type *GetSOAType(int width) const;
const EnumType *GetAsConstType() const;
const EnumType *GetAsNonConstType() const;
std::string GetString() const;
std::string Mangle() const;
std::string GetCDeclaration(const std::string &name) const;
LLVM_TYPE_CONST llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
/** Provides the enumerators defined in the enum definition. */
void SetEnumerators(const std::vector<Symbol *> &enumerators);
/** Returns the total number of enuemrators in this enum type. */
int GetEnumeratorCount() const;
/** Returns the symbol for the given enumerator number. */
const Symbol *GetEnumerator(int i) const;
const SourcePos pos;
private:
const std::string name;
bool isUniform, isConst;
std::vector<Symbol *> enumerators;
};
/** @brief Abstract base class for types that represent collections of
other types.