Inside LLVM, both signed and unsigned integer are represented with the same type - i32 - effectively a signed int32. On 64 bit target, we must generate explicit sxt/zxt during the LLVM IR creation to promote the array index into 64 bit. Otherwise, an unsigned int index becomes signed int index in the LLVM IR.

I limit the fix to uniformed index to avoid widening a varying index vector to 64 bits.  This means that the 32 bit values in the varying indices must be positive and smaller than 2^31 at the runtime for a program to behave correctly.
This commit is contained in:
Peng Tu
2012-11-05 15:02:15 -08:00
parent 9e85667219
commit 04d32ae3e6

View File

@@ -4318,15 +4318,36 @@ IndexExpr::TypeCheck() {
bool isUniform = (index->GetType()->IsUniformType() &&
!g->opt.disableUniformMemoryOptimizations);
// Unless we have an explicit 64-bit index and are compiling to a
// 64-bit target with 64-bit addressing, convert the index to an int32
// type.
if (Type::EqualIgnoringConst(indexType->GetAsUniformType(),
AtomicType::UniformInt64) == false ||
g->target.is32Bit ||
g->opt.force32BitAddressing) {
const Type *indexType = isUniform ? AtomicType::UniformInt32 :
AtomicType::VaryingInt32;
if (!isUniform) {
// Unless we have an explicit 64-bit index and are compiling to a
// 64-bit target with 64-bit addressing, convert the index to an int32
// type.
// The range of varying index is limited to [0,2^31) as a result.
if (Type::EqualIgnoringConst(indexType->GetAsUniformType(),
AtomicType::UniformInt64) == false ||
g->target.is32Bit ||
g->opt.force32BitAddressing) {
const Type *indexType = AtomicType::VaryingInt32;
index = TypeConvertExpr(index, indexType, "array index");
if (index == NULL)
return NULL;
}
} else { // isUniform
// For 32-bit target:
// force the index to 32 bit.
// For 64-bit target:
// We don't want to limit the index range.
// We sxt/zxt the index to 64 bit right here because
// LLVM doesn't distinguish unsigned from signed (both are i32)
//
// However, the index can be still truncated to signed int32 if
// the index type is 64 bit and --addressing=32.
bool force_32bit = g->target.is32Bit ||
(g->opt.force32BitAddressing &&
Type::EqualIgnoringConst(indexType->GetAsUniformType(),
AtomicType::UniformInt64));
const Type *indexType = force_32bit ?
AtomicType::UniformInt32 : AtomicType::UniformInt64;
index = TypeConvertExpr(index, indexType, "array index");
if (index == NULL)
return NULL;