Improvements to constant folding.

We can now do constant folding with all basic datatypes (the previous
implementation handled int32 well, but had limited, if any, coverage
for other datatypes.)

Reduced a bit of repeated code in the constant folding implementation
through template helper functions.
This commit is contained in:
Matt Pharr
2013-07-22 16:12:02 -07:00
parent abf43ad01d
commit 564e61c828
7 changed files with 267 additions and 270 deletions

View File

@@ -446,7 +446,7 @@ lCheckAllOffSafety(ASTNode *node, void *data) {
}
int32_t indices[ISPC_MAX_NVEC];
int count = ce->AsInt32(indices);
int count = ce->GetValues(indices);
for (int i = 0; i < count; ++i) {
if (indices[i] < 0 || indices[i] >= nElements) {
// Index is out of bounds -> not safe

445
expr.cpp
View File

@@ -180,7 +180,7 @@ lIsAllIntZeros(Expr *expr) {
return false;
uint64_t vals[ISPC_MAX_NVEC];
int count = ce->AsUInt64(vals);
int count = ce->GetValues(vals);
if (count == 1)
return (vals[0] == 0);
else {
@@ -1161,6 +1161,16 @@ UnaryExpr::GetType() const {
}
template <typename T> static Expr *
lOptimizeBitNot(ConstExpr *constExpr, const Type *type, SourcePos pos) {
T v[ISPC_MAX_NVEC];
int count = constExpr->GetValues(v);
for (int i = 0; i < count; ++i)
v[i] = ~v[i];
return new ConstExpr(type, v, pos);
}
Expr *
UnaryExpr::Optimize() {
ConstExpr *constExpr = dynamic_cast<ConstExpr *>(expr);
@@ -1172,17 +1182,6 @@ UnaryExpr::Optimize() {
const Type *type = constExpr->GetType();
bool isEnumType = CastType<EnumType>(type) != NULL;
const Type *baseType = type->GetAsNonConstType()->GetAsUniformType();
if (Type::Equal(baseType, AtomicType::UniformInt8) ||
Type::Equal(baseType, AtomicType::UniformUInt8) ||
Type::Equal(baseType, AtomicType::UniformInt16) ||
Type::Equal(baseType, AtomicType::UniformUInt16) ||
Type::Equal(baseType, AtomicType::UniformInt64) ||
Type::Equal(baseType, AtomicType::UniformUInt64))
// FIXME: should handle these at some point; for now we only do
// constant folding for bool, int32 and float types...
return this;
switch (op) {
case PreInc:
case PreDec:
@@ -1192,42 +1191,76 @@ UnaryExpr::Optimize() {
// An error will be issued elsewhere...
return this;
case Negate: {
// Since we currently only handle int32, floats, and doubles here,
// it's safe to stuff whatever we have into a double, do the negate
// as a double, and then return a ConstExpr with the same type as
// the original...
double v[ISPC_MAX_NVEC];
int count = constExpr->AsDouble(v);
for (int i = 0; i < count; ++i)
v[i] = -v[i];
return new ConstExpr(constExpr, v);
if (Type::EqualIgnoringConst(type, AtomicType::UniformInt64) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingInt64)) {
int64_t v[ISPC_MAX_NVEC];
int count = constExpr->GetValues(v);
for (int i = 0; i < count; ++i)
v[i] = -v[i];
return new ConstExpr(type, v, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformUInt64) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingUInt64)) {
uint64_t v[ISPC_MAX_NVEC];
int count = constExpr->GetValues(v);
for (int i = 0; i < count; ++i)
v[i] = -v[i];
return new ConstExpr(type, v, pos);
}
else {
// For all the other types, it's safe to stuff whatever we have
// into a double, do the negate as a double, and then return a
// ConstExpr with the same type as the original...
double v[ISPC_MAX_NVEC];
int count = constExpr->GetValues(v);
for (int i = 0; i < count; ++i)
v[i] = -v[i];
return new ConstExpr(constExpr, v);
}
}
case BitNot: {
if (Type::EqualIgnoringConst(type, AtomicType::UniformInt32) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingInt32)) {
int32_t v[ISPC_MAX_NVEC];
int count = constExpr->AsInt32(v);
for (int i = 0; i < count; ++i)
v[i] = ~v[i];
return new ConstExpr(type, v, pos);
if (Type::EqualIgnoringConst(type, AtomicType::UniformInt8) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingInt8)) {
return lOptimizeBitNot<int8_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformUInt8) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingUInt8)) {
return lOptimizeBitNot<uint8_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformInt16) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingInt16)) {
return lOptimizeBitNot<int16_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformUInt16) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingUInt16)) {
return lOptimizeBitNot<uint16_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformInt32) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingInt32)) {
return lOptimizeBitNot<int32_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformUInt32) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingUInt32) ||
isEnumType == true) {
uint32_t v[ISPC_MAX_NVEC];
int count = constExpr->AsUInt32(v);
for (int i = 0; i < count; ++i)
v[i] = ~v[i];
return new ConstExpr(type, v, pos);
return lOptimizeBitNot<uint32_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformInt64) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingInt64)) {
return lOptimizeBitNot<int64_t>(constExpr, type, pos);
}
else if (Type::EqualIgnoringConst(type, AtomicType::UniformUInt64) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingUInt64) ||
isEnumType == true) {
return lOptimizeBitNot<uint64_t>(constExpr, type, pos);
}
else
FATAL("unexpected type in UnaryExpr::Optimize() / BitNot case");
}
case LogicalNot: {
AssertPos(pos, Type::EqualIgnoringConst(type, AtomicType::UniformBool) ||
Type::EqualIgnoringConst(type, AtomicType::VaryingBool));
Type::EqualIgnoringConst(type, AtomicType::VaryingBool));
bool v[ISPC_MAX_NVEC];
int count = constExpr->AsBool(v);
int count = constExpr->GetValues(v);
for (int i = 0; i < count; ++i)
v[i] = !v[i];
return new ConstExpr(type, v, pos);
@@ -2016,25 +2049,37 @@ BinaryExpr::GetType() const {
#define FOLD_OP(O, E) \
case O: \
for (int i = 0; i < count; ++i) \
result[i] = (v0[i] E v1[i]); \
break
for (int i = 0; i < count; ++i) \
result[i] = (v0[i] E v1[i]); \
break
#define FOLD_OP_REF(O, E, TRef) \
case O: \
for (int i = 0; i < count; ++i) { \
result[i] = (v0[i] E v1[i]); \
TRef r = (TRef)v0[i] E (TRef)v1[i]; \
if (result[i] != r) \
Warning(pos, "Binary expression with type \"%s\" can't represent value.", \
carg0->GetType()->GetString().c_str()); \
} \
break
/** Constant fold the binary integer operations that aren't also applicable
to floating-point types.
*/
template <typename T> static ConstExpr *
lConstFoldBinIntOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *carg0) {
template <typename T, typename TRef> static ConstExpr *
lConstFoldBinaryIntOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *carg0,
SourcePos pos) {
T result[ISPC_MAX_NVEC];
int count = carg0->Count();
switch (op) {
FOLD_OP(BinaryExpr::Mod, %);
FOLD_OP(BinaryExpr::Shl, <<);
FOLD_OP(BinaryExpr::Shr, >>);
FOLD_OP(BinaryExpr::BitAnd, &);
FOLD_OP(BinaryExpr::BitXor, ^);
FOLD_OP(BinaryExpr::BitOr, |);
FOLD_OP_REF(BinaryExpr::Mod, %, TRef);
FOLD_OP_REF(BinaryExpr::Shl, <<, TRef);
FOLD_OP_REF(BinaryExpr::Shr, >>, TRef);
FOLD_OP_REF(BinaryExpr::BitAnd, &, TRef);
FOLD_OP_REF(BinaryExpr::BitXor, ^, TRef);
FOLD_OP_REF(BinaryExpr::BitOr, |, TRef);
default:
return NULL;
}
@@ -2046,7 +2091,8 @@ lConstFoldBinIntOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *carg0
/** Constant fold the binary logical ops.
*/
template <typename T> static ConstExpr *
lConstFoldBinLogicalOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *carg0) {
lConstFoldBinaryLogicalOp(BinaryExpr::Op op, const T *v0, const T *v1,
ConstExpr *carg0) {
bool result[ISPC_MAX_NVEC];
int count = carg0->Count();
@@ -2071,16 +2117,16 @@ lConstFoldBinLogicalOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *c
/** Constant fold binary arithmetic ops.
*/
template <typename T> static ConstExpr *
lConstFoldBinArithOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *carg0,
SourcePos pos) {
template <typename T, typename TRef> static ConstExpr *
lConstFoldBinaryArithOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *carg0,
SourcePos pos) {
T result[ISPC_MAX_NVEC];
int count = carg0->Count();
switch (op) {
FOLD_OP(BinaryExpr::Add, +);
FOLD_OP(BinaryExpr::Sub, -);
FOLD_OP(BinaryExpr::Mul, *);
FOLD_OP_REF(BinaryExpr::Add, +, TRef);
FOLD_OP_REF(BinaryExpr::Sub, -, TRef);
FOLD_OP_REF(BinaryExpr::Mul, *, TRef);
case BinaryExpr::Div:
for (int i = 0; i < count; ++i) {
if (v1[i] == 0) {
@@ -2102,8 +2148,8 @@ lConstFoldBinArithOp(BinaryExpr::Op op, const T *v0, const T *v1, ConstExpr *car
/** Constant fold the various boolean binary ops.
*/
static ConstExpr *
lConstFoldBoolBinOp(BinaryExpr::Op op, const bool *v0, const bool *v1,
ConstExpr *carg0) {
lConstFoldBoolBinaryOp(BinaryExpr::Op op, const bool *v0, const bool *v1,
ConstExpr *carg0) {
bool result[ISPC_MAX_NVEC];
int count = carg0->Count();
@@ -2127,6 +2173,40 @@ lConstFoldBoolBinOp(BinaryExpr::Op op, const bool *v0, const bool *v1,
}
template <typename T> static Expr *
lConstFoldBinaryFPOp(ConstExpr *constArg0, ConstExpr *constArg1,
BinaryExpr::Op op, BinaryExpr *origExpr, SourcePos pos) {
T v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->GetValues(v0);
constArg1->GetValues(v1);
ConstExpr *ret;
if ((ret = lConstFoldBinaryArithOp<T, T>(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinaryLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return origExpr;
}
template <typename T, typename TRef> static Expr *
lConstFoldBinaryIntOp(ConstExpr *constArg0, ConstExpr *constArg1,
BinaryExpr::Op op, BinaryExpr *origExpr, SourcePos pos) {
T v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->GetValues(v0);
constArg1->GetValues(v1);
ConstExpr *ret;
if ((ret = lConstFoldBinaryArithOp<T, TRef>(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinaryIntOp<T, TRef>(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinaryLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return origExpr;
}
Expr *
BinaryExpr::Optimize() {
if (arg0 == NULL || arg1 == NULL)
@@ -2144,7 +2224,7 @@ BinaryExpr::Optimize() {
if (Type::EqualIgnoringConst(type1, AtomicType::UniformFloat) ||
Type::EqualIgnoringConst(type1, AtomicType::VaryingFloat)) {
float inv[ISPC_MAX_NVEC];
int count = constArg1->AsFloat(inv);
int count = constArg1->GetValues(inv);
for (int i = 0; i < count; ++i)
inv[i] = 1.f / inv[i];
Expr *einv = new ConstExpr(type1, inv, constArg1->pos);
@@ -2198,70 +2278,53 @@ BinaryExpr::Optimize() {
const Type *type = arg0->GetType()->GetAsNonConstType();
if (Type::Equal(type, AtomicType::UniformFloat) ||
Type::Equal(type, AtomicType::VaryingFloat)) {
float v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->AsFloat(v0);
constArg1->AsFloat(v1);
ConstExpr *ret;
if ((ret = lConstFoldBinArithOp(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return this;
return lConstFoldBinaryFPOp<float>(constArg0, constArg1, op, this, pos);
}
if (Type::Equal(type, AtomicType::UniformDouble) ||
Type::Equal(type, AtomicType::VaryingDouble)) {
double v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->AsDouble(v0);
constArg1->AsDouble(v1);
ConstExpr *ret;
if ((ret = lConstFoldBinArithOp(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return this;
else if (Type::Equal(type, AtomicType::UniformDouble) ||
Type::Equal(type, AtomicType::VaryingDouble)) {
return lConstFoldBinaryFPOp<double>(constArg0, constArg1, op, this, pos);
}
if (Type::Equal(type, AtomicType::UniformInt32) ||
Type::Equal(type, AtomicType::VaryingInt32)) {
int32_t v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->AsInt32(v0);
constArg1->AsInt32(v1);
ConstExpr *ret;
if ((ret = lConstFoldBinArithOp(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinIntOp(op, v0, v1, constArg0)) != NULL)
return ret;
else if ((ret = lConstFoldBinLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return this;
else if (Type::Equal(type, AtomicType::UniformInt8) ||
Type::Equal(type, AtomicType::VaryingInt8)) {
return lConstFoldBinaryIntOp<int8_t, int64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformUInt8) ||
Type::Equal(type, AtomicType::VaryingUInt8)) {
return lConstFoldBinaryIntOp<uint8_t, uint64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformInt16) ||
Type::Equal(type, AtomicType::VaryingInt16)) {
return lConstFoldBinaryIntOp<int16_t, int64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformUInt16) ||
Type::Equal(type, AtomicType::VaryingUInt16)) {
return lConstFoldBinaryIntOp<uint16_t, uint64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformInt32) ||
Type::Equal(type, AtomicType::VaryingInt32)) {
return lConstFoldBinaryIntOp<int32_t, int64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformUInt32) ||
Type::Equal(type, AtomicType::VaryingUInt32) ||
CastType<EnumType>(type) != NULL) {
uint32_t v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->AsUInt32(v0);
constArg1->AsUInt32(v1);
ConstExpr *ret;
if ((ret = lConstFoldBinArithOp(op, v0, v1, constArg0, pos)) != NULL)
return ret;
else if ((ret = lConstFoldBinIntOp(op, v0, v1, constArg0)) != NULL)
return ret;
else if ((ret = lConstFoldBinLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return this;
Type::Equal(type, AtomicType::VaryingUInt32)) {
return lConstFoldBinaryIntOp<uint32_t, uint64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformInt64) ||
Type::Equal(type, AtomicType::VaryingInt64)) {
return lConstFoldBinaryIntOp<int64_t, int64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformUInt64) ||
Type::Equal(type, AtomicType::VaryingUInt64)) {
return lConstFoldBinaryIntOp<uint64_t, uint64_t>(constArg0, constArg1, op, this, pos);
}
else if (Type::Equal(type, AtomicType::UniformBool) ||
Type::Equal(type, AtomicType::VaryingBool)) {
bool v0[ISPC_MAX_NVEC], v1[ISPC_MAX_NVEC];
constArg0->AsBool(v0);
constArg1->AsBool(v1);
constArg0->GetValues(v0);
constArg1->GetValues(v1);
ConstExpr *ret;
if ((ret = lConstFoldBoolBinOp(op, v0, v1, constArg0)) != NULL)
if ((ret = lConstFoldBoolBinaryOp(op, v0, v1, constArg0)) != NULL)
return ret;
else if ((ret = lConstFoldBinLogicalOp(op, v0, v1, constArg0)) != NULL)
else if ((ret = lConstFoldBinaryLogicalOp(op, v0, v1, constArg0)) != NULL)
return ret;
else
return this;
@@ -3159,6 +3222,19 @@ SelectExpr::GetType() const {
}
template <typename T> Expr *
lConstFoldSelect(const bool bv[], ConstExpr *constExpr1, ConstExpr *constExpr2,
const Type *exprType, SourcePos pos) {
T v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
T result[ISPC_MAX_NVEC];
int count = constExpr1->GetValues(v1);
constExpr2->GetValues(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
}
Expr *
SelectExpr::Optimize() {
if (test == NULL || expr1 == NULL || expr2 == NULL)
@@ -3171,7 +3247,7 @@ SelectExpr::Optimize() {
// The test is a constant; see if we can resolve to one of the
// expressions..
bool bv[ISPC_MAX_NVEC];
int count = constTest->AsBool(bv);
int count = constTest->GetValues(bv);
if (count == 1)
// Uniform test value; return the corresponding expression
return (bv[0] == true) ? expr1 : expr2;
@@ -3200,71 +3276,38 @@ SelectExpr::Optimize() {
const Type *exprType = constExpr1->GetType()->GetAsNonConstType();
AssertPos(pos, exprType->IsVaryingType());
// FIXME: it's annoying to have to have all of this replicated code.
// FIXME: for completeness, it would also be nice to handle 8 and
// 16 bit types...
if (Type::Equal(exprType, AtomicType::VaryingInt32)) {
int32_t v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
int32_t result[ISPC_MAX_NVEC];
constExpr1->AsInt32(v1);
constExpr2->AsInt32(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
if (Type::Equal(exprType, AtomicType::VaryingInt8)) {
return lConstFoldSelect<int8_t>(bv, constExpr1, constExpr2, exprType, pos);
}
if (Type::Equal(exprType, AtomicType::VaryingUInt32)) {
uint32_t v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
uint32_t result[ISPC_MAX_NVEC];
constExpr1->AsUInt32(v1);
constExpr2->AsUInt32(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
else if (Type::Equal(exprType, AtomicType::VaryingUInt8)) {
return lConstFoldSelect<uint8_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingInt16)) {
return lConstFoldSelect<int16_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingUInt16)) {
return lConstFoldSelect<uint16_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingInt32)) {
return lConstFoldSelect<int32_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingUInt32)) {
return lConstFoldSelect<uint32_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingInt64)) {
int64_t v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
int64_t result[ISPC_MAX_NVEC];
constExpr1->AsInt64(v1);
constExpr2->AsInt64(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
return lConstFoldSelect<int64_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingUInt64)) {
uint64_t v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
uint64_t result[ISPC_MAX_NVEC];
constExpr1->AsUInt64(v1);
constExpr2->AsUInt64(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
return lConstFoldSelect<uint64_t>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingFloat)) {
float v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
float result[ISPC_MAX_NVEC];
constExpr1->AsFloat(v1);
constExpr2->AsFloat(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
return lConstFoldSelect<float>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingDouble)) {
double v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
double result[ISPC_MAX_NVEC];
constExpr1->AsDouble(v1);
constExpr2->AsDouble(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
return lConstFoldSelect<bool>(bv, constExpr1, constExpr2, exprType, pos);
}
else if (Type::Equal(exprType, AtomicType::VaryingBool)) {
bool v1[ISPC_MAX_NVEC], v2[ISPC_MAX_NVEC];
bool result[ISPC_MAX_NVEC];
constExpr1->AsBool(v1);
constExpr2->AsBool(v2);
for (int i = 0; i < count; ++i)
result[i] = bv[i] ? v1[i] : v2[i];
return new ConstExpr(exprType, result, pos);
return lConstFoldSelect<double>(bv, constExpr1, constExpr2, exprType, pos);
}
return this;
@@ -4171,7 +4214,7 @@ lCheckIndicesVersusBounds(const Type *baseExprType, Expr *index) {
return;
int32_t indices[ISPC_MAX_NVEC];
int count = ce->AsInt32(indices);
int count = ce->GetValues(indices);
for (int i = 0; i < count; ++i) {
if (indices[i] < 0 || indices[i] >= nElements)
Warning(index->pos, "Array index \"%d\" may be out of bounds for %d "
@@ -5532,7 +5575,7 @@ lConvert(const From *from, To *to, int count, bool forceVarying) {
int
ConstExpr::AsInt64(int64_t *ip, bool forceVarying) const {
ConstExpr::GetValues(int64_t *ip, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, ip, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, ip, Count(), forceVarying); break;
@@ -5553,7 +5596,7 @@ ConstExpr::AsInt64(int64_t *ip, bool forceVarying) const {
int
ConstExpr::AsUInt64(uint64_t *up, bool forceVarying) const {
ConstExpr::GetValues(uint64_t *up, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, up, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, up, Count(), forceVarying); break;
@@ -5574,7 +5617,7 @@ ConstExpr::AsUInt64(uint64_t *up, bool forceVarying) const {
int
ConstExpr::AsDouble(double *d, bool forceVarying) const {
ConstExpr::GetValues(double *d, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, d, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, d, Count(), forceVarying); break;
@@ -5595,7 +5638,7 @@ ConstExpr::AsDouble(double *d, bool forceVarying) const {
int
ConstExpr::AsFloat(float *fp, bool forceVarying) const {
ConstExpr::GetValues(float *fp, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, fp, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, fp, Count(), forceVarying); break;
@@ -5616,7 +5659,7 @@ ConstExpr::AsFloat(float *fp, bool forceVarying) const {
int
ConstExpr::AsBool(bool *b, bool forceVarying) const {
ConstExpr::GetValues(bool *b, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, b, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, b, Count(), forceVarying); break;
@@ -5637,7 +5680,7 @@ ConstExpr::AsBool(bool *b, bool forceVarying) const {
int
ConstExpr::AsInt8(int8_t *ip, bool forceVarying) const {
ConstExpr::GetValues(int8_t *ip, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, ip, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, ip, Count(), forceVarying); break;
@@ -5658,7 +5701,7 @@ ConstExpr::AsInt8(int8_t *ip, bool forceVarying) const {
int
ConstExpr::AsUInt8(uint8_t *up, bool forceVarying) const {
ConstExpr::GetValues(uint8_t *up, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, up, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, up, Count(), forceVarying); break;
@@ -5679,7 +5722,7 @@ ConstExpr::AsUInt8(uint8_t *up, bool forceVarying) const {
int
ConstExpr::AsInt16(int16_t *ip, bool forceVarying) const {
ConstExpr::GetValues(int16_t *ip, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, ip, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, ip, Count(), forceVarying); break;
@@ -5700,7 +5743,7 @@ ConstExpr::AsInt16(int16_t *ip, bool forceVarying) const {
int
ConstExpr::AsUInt16(uint16_t *up, bool forceVarying) const {
ConstExpr::GetValues(uint16_t *up, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, up, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, up, Count(), forceVarying); break;
@@ -5721,7 +5764,7 @@ ConstExpr::AsUInt16(uint16_t *up, bool forceVarying) const {
int
ConstExpr::AsInt32(int32_t *ip, bool forceVarying) const {
ConstExpr::GetValues(int32_t *ip, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, ip, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, ip, Count(), forceVarying); break;
@@ -5742,7 +5785,7 @@ ConstExpr::AsInt32(int32_t *ip, bool forceVarying) const {
int
ConstExpr::AsUInt32(uint32_t *up, bool forceVarying) const {
ConstExpr::GetValues(uint32_t *up, bool forceVarying) const {
switch (getBasicType()) {
case AtomicType::TYPE_BOOL: lConvert(boolVal, up, Count(), forceVarying); break;
case AtomicType::TYPE_INT8: lConvert(int8Val, up, Count(), forceVarying); break;
@@ -5779,7 +5822,7 @@ ConstExpr::GetConstant(const Type *type) const {
if (Type::Equal(type, AtomicType::UniformBool) ||
Type::Equal(type, AtomicType::VaryingBool)) {
bool bv[ISPC_MAX_NVEC];
AsBool(bv, type->IsVaryingType());
GetValues(bv, type->IsVaryingType());
if (type->IsUniformType())
return bv[0] ? LLVMTrue : LLVMFalse;
else
@@ -5788,7 +5831,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformInt8) ||
Type::Equal(type, AtomicType::VaryingInt8)) {
int8_t iv[ISPC_MAX_NVEC];
AsInt8(iv, type->IsVaryingType());
GetValues(iv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMInt8(iv[0]);
else
@@ -5797,7 +5840,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformUInt8) ||
Type::Equal(type, AtomicType::VaryingUInt8)) {
uint8_t uiv[ISPC_MAX_NVEC];
AsUInt8(uiv, type->IsVaryingType());
GetValues(uiv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMUInt8(uiv[0]);
else
@@ -5806,7 +5849,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformInt16) ||
Type::Equal(type, AtomicType::VaryingInt16)) {
int16_t iv[ISPC_MAX_NVEC];
AsInt16(iv, type->IsVaryingType());
GetValues(iv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMInt16(iv[0]);
else
@@ -5815,7 +5858,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformUInt16) ||
Type::Equal(type, AtomicType::VaryingUInt16)) {
uint16_t uiv[ISPC_MAX_NVEC];
AsUInt16(uiv, type->IsVaryingType());
GetValues(uiv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMUInt16(uiv[0]);
else
@@ -5824,7 +5867,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformInt32) ||
Type::Equal(type, AtomicType::VaryingInt32)) {
int32_t iv[ISPC_MAX_NVEC];
AsInt32(iv, type->IsVaryingType());
GetValues(iv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMInt32(iv[0]);
else
@@ -5834,7 +5877,7 @@ ConstExpr::GetConstant(const Type *type) const {
Type::Equal(type, AtomicType::VaryingUInt32) ||
CastType<EnumType>(type) != NULL) {
uint32_t uiv[ISPC_MAX_NVEC];
AsUInt32(uiv, type->IsVaryingType());
GetValues(uiv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMUInt32(uiv[0]);
else
@@ -5843,7 +5886,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformFloat) ||
Type::Equal(type, AtomicType::VaryingFloat)) {
float fv[ISPC_MAX_NVEC];
AsFloat(fv, type->IsVaryingType());
GetValues(fv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMFloat(fv[0]);
else
@@ -5852,7 +5895,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformInt64) ||
Type::Equal(type, AtomicType::VaryingInt64)) {
int64_t iv[ISPC_MAX_NVEC];
AsInt64(iv, type->IsVaryingType());
GetValues(iv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMInt64(iv[0]);
else
@@ -5861,7 +5904,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformUInt64) ||
Type::Equal(type, AtomicType::VaryingUInt64)) {
uint64_t uiv[ISPC_MAX_NVEC];
AsUInt64(uiv, type->IsVaryingType());
GetValues(uiv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMUInt64(uiv[0]);
else
@@ -5870,7 +5913,7 @@ ConstExpr::GetConstant(const Type *type) const {
else if (Type::Equal(type, AtomicType::UniformDouble) ||
Type::Equal(type, AtomicType::VaryingDouble)) {
double dv[ISPC_MAX_NVEC];
AsDouble(dv, type->IsVaryingType());
GetValues(dv, type->IsVaryingType());
if (type->IsUniformType())
return LLVMDouble(dv[0]);
else
@@ -5887,7 +5930,7 @@ ConstExpr::GetConstant(const Type *type) const {
}
int64_t iv[ISPC_MAX_NVEC];
AsInt64(iv, type->IsVaryingType());
GetValues(iv, type->IsVaryingType());
for (int i = 0; i < Count(); ++i)
if (iv[i] != 0)
// We'll issue an error about this later--trying to assign
@@ -6976,64 +7019,64 @@ TypeCastExpr::Optimize() {
bool forceVarying = toType->IsVaryingType();
// All of the type conversion smarts we need is already in the
// ConstExpr::AsBool(), etc., methods, so we just need to call the
// ConstExpr::GetValues(), etc., methods, so we just need to call the
// appropriate one for the type that this cast is converting to.
AtomicType::BasicType basicType = toAtomic ? toAtomic->basicType :
AtomicType::TYPE_UINT32;
switch (basicType) {
case AtomicType::TYPE_BOOL: {
bool bv[ISPC_MAX_NVEC];
constExpr->AsBool(bv, forceVarying);
constExpr->GetValues(bv, forceVarying);
return new ConstExpr(toType, bv, pos);
}
case AtomicType::TYPE_INT8: {
int8_t iv[ISPC_MAX_NVEC];
constExpr->AsInt8(iv, forceVarying);
constExpr->GetValues(iv, forceVarying);
return new ConstExpr(toType, iv, pos);
}
case AtomicType::TYPE_UINT8: {
uint8_t uv[ISPC_MAX_NVEC];
constExpr->AsUInt8(uv, forceVarying);
constExpr->GetValues(uv, forceVarying);
return new ConstExpr(toType, uv, pos);
}
case AtomicType::TYPE_INT16: {
int16_t iv[ISPC_MAX_NVEC];
constExpr->AsInt16(iv, forceVarying);
constExpr->GetValues(iv, forceVarying);
return new ConstExpr(toType, iv, pos);
}
case AtomicType::TYPE_UINT16: {
uint16_t uv[ISPC_MAX_NVEC];
constExpr->AsUInt16(uv, forceVarying);
constExpr->GetValues(uv, forceVarying);
return new ConstExpr(toType, uv, pos);
}
case AtomicType::TYPE_INT32: {
int32_t iv[ISPC_MAX_NVEC];
constExpr->AsInt32(iv, forceVarying);
constExpr->GetValues(iv, forceVarying);
return new ConstExpr(toType, iv, pos);
}
case AtomicType::TYPE_UINT32: {
uint32_t uv[ISPC_MAX_NVEC];
constExpr->AsUInt32(uv, forceVarying);
constExpr->GetValues(uv, forceVarying);
return new ConstExpr(toType, uv, pos);
}
case AtomicType::TYPE_FLOAT: {
float fv[ISPC_MAX_NVEC];
constExpr->AsFloat(fv, forceVarying);
constExpr->GetValues(fv, forceVarying);
return new ConstExpr(toType, fv, pos);
}
case AtomicType::TYPE_INT64: {
int64_t iv[ISPC_MAX_NVEC];
constExpr->AsInt64(iv, forceVarying);
constExpr->GetValues(iv, forceVarying);
return new ConstExpr(toType, iv, pos);
}
case AtomicType::TYPE_UINT64: {
uint64_t uv[ISPC_MAX_NVEC];
constExpr->AsUInt64(uv, forceVarying);
constExpr->GetValues(uv, forceVarying);
return new ConstExpr(toType, uv, pos);
}
case AtomicType::TYPE_DOUBLE: {
double dv[ISPC_MAX_NVEC];
constExpr->AsDouble(dv, forceVarying);
constExpr->GetValues(dv, forceVarying);
return new ConstExpr(toType, dv, pos);
}
default:

81
expr.h
View File

@@ -409,71 +409,22 @@ public:
Expr *Optimize();
int EstimateCost() const;
/** Return the ConstExpr's values as booleans, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsBool(bool *, bool forceVarying = false) const;
/** Return the ConstExpr's values as int8s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsInt8(int8_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as uint8s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsUInt8(uint8_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as int16s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsInt16(int16_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as uint16s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsUInt16(uint16_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as int32s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsInt32(int32_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as uint32s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsUInt32(uint32_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as floats, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsFloat(float *, bool forceVarying = false) const;
/** Return the ConstExpr's values as int64s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsInt64(int64_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as uint64s, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsUInt64(uint64_t *, bool forceVarying = false) const;
/** Return the ConstExpr's values as doubles, doing type conversion
from the actual type if needed. If forceVarying is true, then type
convert to 'varying' so as to always return a number of values
equal to the target vector width into the given pointer. */
int AsDouble(double *, bool forceVarying = false) const;
/** Return the ConstExpr's values as the given pointer type, doing type
conversion from the actual type if needed. If forceVarying is
true, then type convert to 'varying' so as to always return a
number of values equal to the target vector width into the given
pointer. */
int GetValues(bool *, bool forceVarying = false) const;
int GetValues(int8_t *, bool forceVarying = false) const;
int GetValues(uint8_t *, bool forceVarying = false) const;
int GetValues(int16_t *, bool forceVarying = false) const;
int GetValues(uint16_t *, bool forceVarying = false) const;
int GetValues(int32_t *, bool forceVarying = false) const;
int GetValues(uint32_t *, bool forceVarying = false) const;
int GetValues(float *, bool forceVarying = false) const;
int GetValues(int64_t *, bool forceVarying = false) const;
int GetValues(uint64_t *, bool forceVarying = false) const;
int GetValues(double *, bool forceVarying = false) const;
/** Return the number of values in the ConstExpr; should be either 1,
if it has uniform type, or the target's vector width if it's

View File

@@ -1196,7 +1196,7 @@ lEmitEnumDecls(const std::vector<const EnumType *> &enumTypes, FILE *file) {
const Symbol *e = enumTypes[i]->GetEnumerator(j);
Assert(e->constValue != NULL);
unsigned int enumValue;
int count = e->constValue->AsUInt32(&enumValue);
int count = e->constValue->GetValues(&enumValue);
Assert(count == 1);
// Always print an initializer to set the value. We could be

View File

@@ -2287,7 +2287,7 @@ lFinalizeEnumeratorSymbols(std::vector<Symbol *> &enums,
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);
int count = enums[i]->constValue->GetValues(&nextVal);
AssertPos(enums[i]->pos, count == 1);
++nextVal;

View File

@@ -0,0 +1,3 @@
// Binary expression with type "const uniform int8" can't represent value.
int8 v = (int8)64 * (int8)32;

View File

@@ -804,7 +804,7 @@ EnumType::GetDIType(llvm::DIDescriptor scope) const {
for (unsigned int i = 0; i < enumerators.size(); ++i) {
unsigned int enumeratorValue;
Assert(enumerators[i]->constValue != NULL);
int count = enumerators[i]->constValue->AsUInt32(&enumeratorValue);
int count = enumerators[i]->constValue->GetValues(&enumeratorValue);
Assert(count == 1);
llvm::Value *descriptor =