Add support for enums.
This commit is contained in:
8
ctx.cpp
8
ctx.cpp
@@ -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,
|
||||
|
||||
@@ -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
196
expr.cpp
@@ -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
11
expr.h
@@ -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];
|
||||
|
||||
11
ispc.cpp
11
ispc.cpp
@@ -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
4
ispc.h
@@ -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
3
lex.ll
@@ -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);
|
||||
|
||||
220
module.cpp
220
module.cpp
@@ -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
214
parse.yy
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
stmt.cpp
10
stmt.cpp
@@ -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
23
sym.cpp
@@ -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
5
sym.h
@@ -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
16
tests/enum-1.ispc
Normal 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
18
tests/enum-2.ispc
Normal 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
18
tests/enum-3.ispc
Normal 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
26
tests/enum-4.ispc
Normal 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
26
tests/enum-5.ispc
Normal 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
26
tests/enum-6.ispc
Normal 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
27
tests/enum-7.ispc
Normal 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
26
tests/enum-8.ispc
Normal 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
16
tests/enum-9.ispc
Normal 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
283
type.cpp
@@ -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
48
type.h
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user