Pointer fixes/improvements.

Allow <, <=, >, >= comparisons of pointers
Allow explicit type-casting of pointers to and from integers
Fix bug in handling expressions of the form "int + ptr" ("ptr + int"
  was fine).
Fix a bug in TypeCastExpr where varying -> uniform typecasts
  would be allowed (leading to a crash later)
This commit is contained in:
Matt Pharr
2011-11-29 13:22:36 -08:00
parent 4ca90272ba
commit e52104ff55
15 changed files with 235 additions and 40 deletions

123
expr.cpp
View File

@@ -1294,8 +1294,9 @@ BinaryExpr::GetType() const {
// ptr - int -> ptr
return type0;
}
// otherwise fall through for these two...
assert(op == Equal || op == NotEqual);
// otherwise fall through for these...
assert(op == Lt || op == Gt || op == Le || op == Ge ||
op == Equal || op == NotEqual);
}
const Type *exprType = Type::MoreGeneralType(type0, type1, pos, lOpString(op));
@@ -1648,6 +1649,7 @@ BinaryExpr::TypeCheck() {
// put in canonical order with the pointer as the first operand
// for GetValue()
std::swap(arg0, arg1);
std::swap(type0, type1);
std::swap(pt0, pt1);
}
@@ -1726,11 +1728,7 @@ BinaryExpr::TypeCheck() {
case Sub:
case Mul:
case Div:
case Mod:
case Lt:
case Gt:
case Le:
case Ge: {
case Mod: {
// Must be numeric type for these. (And mod is special--can't be float)
if (!type0->IsNumericType() || (op == Mod && type0->IsFloatType())) {
Error(arg0->pos, "First operand to binary operator \"%s\" is of "
@@ -1756,6 +1754,10 @@ BinaryExpr::TypeCheck() {
return NULL;
return this;
}
case Lt:
case Gt:
case Le:
case Ge:
case Equal:
case NotEqual: {
const PointerType *pt0 = dynamic_cast<const PointerType *>(type0);
@@ -1763,14 +1765,14 @@ BinaryExpr::TypeCheck() {
if (pt0 == NULL && pt1 == NULL) {
if (!type0->IsBoolType() && !type0->IsNumericType()) {
Error(arg0->pos,
"First operand to equality operator \"%s\" is of "
"First operand to operator \"%s\" is of "
"non-comparable type \"%s\".", lOpString(op),
type0->GetString().c_str());
return NULL;
}
if (!type1->IsBoolType() && !type1->IsNumericType()) {
Error(arg1->pos,
"Second operand to equality operator \"%s\" is of "
"Second operand to operator \"%s\" is of "
"non-comparable type \"%s\".", lOpString(op),
type1->GetString().c_str());
return NULL;
@@ -5132,30 +5134,46 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
}
}
else {
// convert pointer to bool
assert(dynamic_cast<const AtomicType *>(toType) &&
toType->IsBoolType());
LLVM_TYPE_CONST llvm::Type *lfu =
fromType->GetAsUniformType()->LLVMType(g->ctx);
LLVM_TYPE_CONST llvm::PointerType *llvmFromUnifType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(lfu);
assert(dynamic_cast<const AtomicType *>(toType) != NULL);
if (toType->IsBoolType()) {
// convert pointer to bool
LLVM_TYPE_CONST llvm::Type *lfu =
fromType->GetAsUniformType()->LLVMType(g->ctx);
LLVM_TYPE_CONST llvm::PointerType *llvmFromUnifType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(lfu);
llvm::Value *nullPtrValue = llvm::ConstantPointerNull::get(llvmFromUnifType);
if (fromType->IsVaryingType())
nullPtrValue = ctx->SmearUniform(nullPtrValue);
llvm::Value *nullPtrValue =
llvm::ConstantPointerNull::get(llvmFromUnifType);
if (fromType->IsVaryingType())
nullPtrValue = ctx->SmearUniform(nullPtrValue);
llvm::Value *exprVal = expr->GetValue(ctx);
llvm::Value *cmp = ctx->CmpInst(llvm::Instruction::ICmp,
llvm::CmpInst::ICMP_NE,
exprVal, nullPtrValue, "ptr_ne_NULL");
llvm::Value *exprVal = expr->GetValue(ctx);
llvm::Value *cmp =
ctx->CmpInst(llvm::Instruction::ICmp, llvm::CmpInst::ICMP_NE,
exprVal, nullPtrValue, "ptr_ne_NULL");
if (toType->IsVaryingType()) {
if (fromType->IsUniformType())
cmp = ctx->SmearUniform(cmp);
cmp = ctx->I1VecToBoolVec(cmp);
if (toType->IsVaryingType()) {
if (fromType->IsUniformType())
cmp = ctx->SmearUniform(cmp);
cmp = ctx->I1VecToBoolVec(cmp);
}
return cmp;
}
else {
// ptr -> int
llvm::Value *value = expr->GetValue(ctx);
if (value == NULL)
return NULL;
return cmp;
if (toType->IsVaryingType() && fromType->IsUniformType())
value = ctx->SmearUniform(value);
LLVM_TYPE_CONST llvm::Type *llvmToType = toType->LLVMType(g->ctx);
if (llvmToType == NULL)
return NULL;
return ctx->PtrToIntInst(value, llvmToType, "ptr_typecast");
}
}
}
@@ -5304,6 +5322,17 @@ TypeCastExpr::GetValue(FunctionEmitContext *ctx) const {
cast = ctx->InsertInst(cast, conv, i);
return cast;
}
else if (toPointerType != NULL) {
// int -> ptr
if (toType->IsVaryingType() && fromType->IsUniformType())
exprVal = ctx->SmearUniform(exprVal);
LLVM_TYPE_CONST llvm::Type *llvmToType = toType->LLVMType(g->ctx);
if (llvmToType == NULL)
return NULL;
return ctx->IntToPtrInst(exprVal, llvmToType, "int_to_ptr");
}
else {
const AtomicType *toAtomic = dynamic_cast<const AtomicType *>(toType);
// typechecking should ensure this is the case
@@ -5352,10 +5381,17 @@ TypeCastExpr::TypeCheck() {
fromType = lDeconstifyType(fromType);
toType = lDeconstifyType(toType);
if (fromType->IsVaryingType() && toType->IsUniformType()) {
Error(pos, "Can't type cast from varying type \"%s\" to uniform "
"type \"%s\"", fromType->GetString().c_str(),
toType->GetString().c_str());
return NULL;
}
// First some special cases that we allow only with an explicit type cast
const PointerType *ptFrom = dynamic_cast<const PointerType *>(fromType);
const PointerType *ptTo = dynamic_cast<const PointerType *>(toType);
if (ptFrom != NULL && ptTo != NULL)
const PointerType *fromPtr = dynamic_cast<const PointerType *>(fromType);
const PointerType *toPtr = dynamic_cast<const PointerType *>(toType);
if (fromPtr != NULL && toPtr != NULL)
// allow explicit typecasts between any two different pointer types
return this;
@@ -5367,6 +5403,25 @@ TypeCastExpr::TypeCheck() {
// Allow explicit casts between all of these
return this;
// ptr -> int type casts
if (fromPtr != NULL && toAtomic != NULL && toAtomic->IsIntType()) {
bool safeCast = (toAtomic->basicType == AtomicType::TYPE_INT64 ||
toAtomic->basicType == AtomicType::TYPE_UINT64);
if (g->target.is32Bit)
safeCast |= (toAtomic->basicType == AtomicType::TYPE_INT32 ||
toAtomic->basicType == AtomicType::TYPE_UINT32);
if (safeCast == false)
Warning(pos, "Pointer type cast of type \"%s\" to integer type "
"\"%s\" may lose information.",
fromType->GetString().c_str(),
toType->GetString().c_str());
return this;
}
// int -> ptr
if (fromAtomic != NULL && fromAtomic->IsIntType() && toPtr != NULL)
return this;
// And otherwise see if it's one of the conversions allowed to happen
// implicitly.
if (CanConvertTypes(fromType, toType, "type cast expression", pos) == false)
@@ -5483,6 +5538,12 @@ TypeCastExpr::Print() const {
}
Symbol *
TypeCastExpr::GetBaseSymbol() const {
return expr ? expr->GetBaseSymbol() : NULL;
}
llvm::Constant *
TypeCastExpr::GetConstant(const Type *constType) const {
// We don't need to worry about most the basic cases where the type