diff --git a/ctx.cpp b/ctx.cpp index 95840aab..a3702d7a 100644 --- a/ctx.cpp +++ b/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(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(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(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; } diff --git a/ctx.h b/ctx.h index b4472f1c..298167a5 100644 --- a/ctx.h +++ b/ctx.h @@ -41,9 +41,7 @@ #include "ispc.h" #include #include -#ifndef LLVM_2_8 #include -#endif #include 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); diff --git a/expr.cpp b/expr.cpp index f6800b3d..c8c8bdfc 100644 --- a/expr.cpp +++ b/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(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(toType) && - toType->IsBoolType()); - LLVM_TYPE_CONST llvm::Type *lfu = - fromType->GetAsUniformType()->LLVMType(g->ctx); - LLVM_TYPE_CONST llvm::PointerType *llvmFromUnifType = - llvm::dyn_cast(lfu); + assert(dynamic_cast(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(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(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(fromType); - const PointerType *ptTo = dynamic_cast(toType); - if (ptFrom != NULL && ptTo != NULL) + const PointerType *fromPtr = dynamic_cast(fromType); + const PointerType *toPtr = dynamic_cast(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 diff --git a/expr.h b/expr.h index a6720c03..4de7ddb1 100644 --- a/expr.h +++ b/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; diff --git a/opt.cpp b/opt.cpp index 9999a469..fade6563 100644 --- a/opt.cpp +++ b/opt.cpp @@ -63,7 +63,7 @@ #include #else #include -#endif // LLVM_2_8 +#endif // LLVM_2_9 #include #include #include diff --git a/run_tests.py b/run_tests.py index 7bc7ebdf..058b10b8 100755 --- a/run_tests.py +++ b/run_tests.py @@ -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) diff --git a/tests/ptr-cmp-1.ispc b/tests/ptr-cmp-1.ispc new file mode 100644 index 00000000..2c32e156 --- /dev/null +++ b/tests/ptr-cmp-1.ispc @@ -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; +} diff --git a/tests/ptr-cmp-2.ispc b/tests/ptr-cmp-2.ispc new file mode 100644 index 00000000..0633011e --- /dev/null +++ b/tests/ptr-cmp-2.ispc @@ -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; +} diff --git a/tests/ptr-diff-4.ispc b/tests/ptr-diff-4.ispc new file mode 100644 index 00000000..89b37813 --- /dev/null +++ b/tests/ptr-diff-4.ispc @@ -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; +} diff --git a/tests/ptr-diff-5.ispc b/tests/ptr-diff-5.ispc new file mode 100644 index 00000000..4fb649aa --- /dev/null +++ b/tests/ptr-diff-5.ispc @@ -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; +} diff --git a/tests/ptr-diff-6.ispc b/tests/ptr-diff-6.ispc new file mode 100644 index 00000000..48d8b25f --- /dev/null +++ b/tests/ptr-diff-6.ispc @@ -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; +} diff --git a/tests/ptr-int-1.ispc b/tests/ptr-int-1.ispc new file mode 100644 index 00000000..1ffbc02f --- /dev/null +++ b/tests/ptr-int-1.ispc @@ -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; +} diff --git a/tests_errors/func-export-task.ispc b/tests_errors/func-export-task.ispc new file mode 100644 index 00000000..d6796b73 --- /dev/null +++ b/tests_errors/func-export-task.ispc @@ -0,0 +1,4 @@ +// Function can't have both "task" and "export" qualifiers + +export task void foo() { +} diff --git a/tests_errors/ptrcast-lose-info.ispc b/tests_errors/ptrcast-lose-info.ispc new file mode 100644 index 00000000..fdaac83b --- /dev/null +++ b/tests_errors/ptrcast-lose-info.ispc @@ -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; +} + diff --git a/tests_errors/vary-to-unif-typecast.ispc b/tests_errors/vary-to-unif-typecast.ispc new file mode 100644 index 00000000..ca60749a --- /dev/null +++ b/tests_errors/vary-to-unif-typecast.ispc @@ -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; +} +