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:
53
ctx.cpp
53
ctx.cpp
@@ -1156,19 +1156,62 @@ FunctionEmitContext::PtrToIntInst(llvm::Value *value, const char *name) {
|
||||
|
||||
|
||||
llvm::Value *
|
||||
FunctionEmitContext::IntToPtrInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type,
|
||||
FunctionEmitContext::PtrToIntInst(llvm::Value *value,
|
||||
LLVM_TYPE_CONST llvm::Type *toType,
|
||||
const char *name) {
|
||||
if (value == NULL) {
|
||||
assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(value->getType()))
|
||||
// no-op for varying pointers; they're already vectors of ints
|
||||
return value;
|
||||
LLVM_TYPE_CONST llvm::Type *fromType = value->getType();
|
||||
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(fromType)) {
|
||||
// varying pointer
|
||||
if (fromType == toType)
|
||||
// already the right type--done
|
||||
return value;
|
||||
else if (fromType->getScalarSizeInBits() > toType->getScalarSizeInBits())
|
||||
return TruncInst(value, toType, "ptr_to_int");
|
||||
else {
|
||||
assert(fromType->getScalarSizeInBits() <
|
||||
toType->getScalarSizeInBits());
|
||||
return ZExtInst(value, toType, "ptr_to_int");
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Instruction *inst =
|
||||
new llvm::IntToPtrInst(value, type, name ? name : "int2ptr", bblock);
|
||||
new llvm::PtrToIntInst(value, toType, name ? name : "ptr2int", bblock);
|
||||
AddDebugPos(inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
llvm::Value *
|
||||
FunctionEmitContext::IntToPtrInst(llvm::Value *value,
|
||||
LLVM_TYPE_CONST llvm::Type *toType,
|
||||
const char *name) {
|
||||
if (value == NULL) {
|
||||
assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLVM_TYPE_CONST llvm::Type *fromType = value->getType();
|
||||
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(fromType)) {
|
||||
// varying pointer
|
||||
if (fromType == toType)
|
||||
// done
|
||||
return value;
|
||||
else if (fromType->getScalarSizeInBits() > toType->getScalarSizeInBits())
|
||||
return TruncInst(value, toType, "int_to_ptr");
|
||||
else {
|
||||
assert(fromType->getScalarSizeInBits() <
|
||||
toType->getScalarSizeInBits());
|
||||
return ZExtInst(value, toType, "int_to_ptr");
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Instruction *inst =
|
||||
new llvm::IntToPtrInst(value, toType, name ? name : "int2ptr", bblock);
|
||||
AddDebugPos(inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
4
ctx.h
4
ctx.h
@@ -41,9 +41,7 @@
|
||||
#include "ispc.h"
|
||||
#include <llvm/InstrTypes.h>
|
||||
#include <llvm/Instructions.h>
|
||||
#ifndef LLVM_2_8
|
||||
#include <llvm/Analysis/DIBuilder.h>
|
||||
#endif
|
||||
#include <llvm/Analysis/DebugInfo.h>
|
||||
|
||||
struct CFInfo;
|
||||
@@ -316,6 +314,8 @@ public:
|
||||
llvm::Value *BitCastInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type,
|
||||
const char *name = NULL);
|
||||
llvm::Value *PtrToIntInst(llvm::Value *value, const char *name = NULL);
|
||||
llvm::Value *PtrToIntInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type,
|
||||
const char *name = NULL);
|
||||
llvm::Value *IntToPtrInst(llvm::Value *value, LLVM_TYPE_CONST llvm::Type *type,
|
||||
const char *name = NULL);
|
||||
|
||||
|
||||
123
expr.cpp
123
expr.cpp
@@ -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
|
||||
|
||||
1
expr.h
1
expr.h
@@ -502,6 +502,7 @@ public:
|
||||
Expr *TypeCheck();
|
||||
Expr *Optimize();
|
||||
int EstimateCost() const;
|
||||
Symbol *GetBaseSymbol() const;
|
||||
llvm::Constant *GetConstant(const Type *type) const;
|
||||
|
||||
const Type *type;
|
||||
|
||||
2
opt.cpp
2
opt.cpp
@@ -63,7 +63,7 @@
|
||||
#include <llvm/Support/StandardPasses.h>
|
||||
#else
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
#endif // LLVM_2_8
|
||||
#endif // LLVM_2_9
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/Transforms/Scalar.h>
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
|
||||
@@ -107,7 +107,7 @@ def run_tasks_from_queue(queue):
|
||||
# is this a test to make sure an error is issued?
|
||||
want_error = (filename.find("tests_errors") != -1)
|
||||
if want_error == True:
|
||||
ispc_cmd = "ispc --nowrap --woff %s --arch=%s --target=%s" % \
|
||||
ispc_cmd = "ispc --nowrap %s --arch=%s --target=%s" % \
|
||||
( filename, options.arch, options.target)
|
||||
sp = subprocess.Popen(shlex.split(ispc_cmd), stdin=None, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
12
tests/ptr-cmp-1.ispc
Normal file
12
tests/ptr-cmp-1.ispc
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform float * varying b = &aFOO[10];
|
||||
uniform float * uniform c = aFOO;
|
||||
RET[programIndex] = (b > c) ? 10 : 0;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 10;
|
||||
}
|
||||
12
tests/ptr-cmp-2.ispc
Normal file
12
tests/ptr-cmp-2.ispc
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform float * uniform b = aFOO;
|
||||
uniform float * uniform c = aFOO;
|
||||
RET[programIndex] = (c <= b) ? 10 : 0;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 10;
|
||||
}
|
||||
12
tests/ptr-diff-4.ispc
Normal file
12
tests/ptr-diff-4.ispc
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform float * varying b = aFOO;
|
||||
b = 5 + b;
|
||||
RET[programIndex] = b - aFOO;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 5;
|
||||
}
|
||||
12
tests/ptr-diff-5.ispc
Normal file
12
tests/ptr-diff-5.ispc
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform float * varying b = aFOO;
|
||||
uniform float * uniform c = &aFOO[10];
|
||||
RET[programIndex] = c - b;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 10;
|
||||
}
|
||||
12
tests/ptr-diff-6.ispc
Normal file
12
tests/ptr-diff-6.ispc
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform float * varying b = &aFOO[10];
|
||||
uniform float * uniform c = aFOO;
|
||||
RET[programIndex] = b - c;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 10;
|
||||
}
|
||||
14
tests/ptr-int-1.ispc
Normal file
14
tests/ptr-int-1.ispc
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform int a = 1;
|
||||
uniform int * uniform b = &a;
|
||||
int64 pi = (int64)b;
|
||||
RET[programIndex] = *((uniform int * varying)pi);
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 1;
|
||||
}
|
||||
4
tests_errors/func-export-task.ispc
Normal file
4
tests_errors/func-export-task.ispc
Normal file
@@ -0,0 +1,4 @@
|
||||
// Function can't have both "task" and "export" qualifiers
|
||||
|
||||
export task void foo() {
|
||||
}
|
||||
6
tests_errors/ptrcast-lose-info.ispc
Normal file
6
tests_errors/ptrcast-lose-info.ispc
Normal file
@@ -0,0 +1,6 @@
|
||||
// Pointer type cast of type "int32 * uniform" to integer type "uniform int32" may lose information.
|
||||
|
||||
int32 foo(int * uniform x) {
|
||||
return (int32) x;
|
||||
}
|
||||
|
||||
6
tests_errors/vary-to-unif-typecast.ispc
Normal file
6
tests_errors/vary-to-unif-typecast.ispc
Normal file
@@ -0,0 +1,6 @@
|
||||
// Can't type cast from varying type "int32" to uniform type "uniform int32"
|
||||
|
||||
uniform int foo(int x) {
|
||||
return (uniform int) x;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user