[llvm-commits] [126210] Fix handling of arrays with var-sized elements
dpatel at apple.com
dpatel at apple.com
Mon Apr 16 13:01:42 PDT 2007
Revision: 126210
Author: dpatel
Date: 2007-04-16 13:01:41 -0700 (Mon, 16 Apr 2007)
Log Message:
-----------
Fix handling of arrays with var-sized elements
Patch by Duncan Sands.
Modified Paths:
--------------
apple-local/branches/llvm/gcc/llvm-abi.h
apple-local/branches/llvm/gcc/llvm-convert.cpp
apple-local/branches/llvm/gcc/llvm-debug.cpp
apple-local/branches/llvm/gcc/llvm-internal.h
apple-local/branches/llvm/gcc/llvm-types.cpp
Modified: apple-local/branches/llvm/gcc/llvm-abi.h
===================================================================
--- apple-local/branches/llvm/gcc/llvm-abi.h 2007-04-16 18:55:33 UTC (rev 126209)
+++ apple-local/branches/llvm/gcc/llvm-abi.h 2007-04-16 20:01:41 UTC (rev 126210)
@@ -110,7 +110,7 @@
}
return FoundField ? isSingleElementStructOrArray(FoundField) : 0;
case ARRAY_TYPE:
- if (TREE_CODE(TYPE_SIZE(type)) != INTEGER_CST)
+ if (!isArrayCompatible(type))
return 0;
tree length = arrayLength(type);
if (!length || !integer_onep(length))
Modified: apple-local/branches/llvm/gcc/llvm-convert.cpp
===================================================================
--- apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-04-16 18:55:33 UTC (rev 126209)
+++ apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-04-16 20:01:41 UTC (rev 126210)
@@ -253,6 +253,35 @@
}
}
+/// isInt64 - Return true if t is an INTEGER_CST that fits in a 64 bit integer.
+/// If Unsigned is false, returns whether it fits in a int64_t. If Unsigned is
+/// true, returns whether the value is non-negative and fits in a uint64_t.
+/// Always returns false for overflowed constants.
+bool isInt64(tree_node *t, bool Unsigned) {
+ if (HOST_BITS_PER_WIDE_INT == 64)
+ return host_integerp(t, Unsigned);
+ else {
+ assert(HOST_BITS_PER_WIDE_INT == 32 &&
+ "Only 32- and 64-bit hosts supported!");
+ return
+ (TREE_CODE (t) == INTEGER_CST && !TREE_OVERFLOW (t))
+ && ((TYPE_UNSIGNED(TREE_TYPE(t)) == Unsigned) ||
+ // If the constant is signed and we want an unsigned result, check
+ // that the value is non-negative. If the constant is unsigned and
+ // we want a signed result, check it fits in 63 bits.
+ (HOST_WIDE_INT)TREE_INT_CST_HIGH(t) >= 0);
+ }
+}
+
+/// getInt64 - Extract the value of an INTEGER_CST as a 64 bit integer. If
+/// Unsigned is false, the value must fit in a int64_t. If Unsigned is true,
+/// the value must be non-negative and fit in a uint64_t. Must not be used on
+/// overflowed constants. These conditions can be checked by calling isInt64.
+uint64_t getInt64(tree_node *t, bool Unsigned) {
+ assert(isInt64(t, Unsigned) && "invalid constant!");
+ return getINTEGER_CSTVal(t);
+}
+
//===----------------------------------------------------------------------===//
// ... High-Level Methods ...
//===----------------------------------------------------------------------===//
@@ -1374,16 +1403,18 @@
tree length;
// Dynamic-size object: must push space on the stack.
- if (TREE_CODE(type) == ARRAY_TYPE && (length = arrayLength(type))) {
+ if (TREE_CODE(type) == ARRAY_TYPE &&
+ isSequentialCompatible(type) &&
+ (length = arrayLength(type))) {
Ty = ConvertType(TREE_TYPE(type)); // Get array element type.
// Compute the number of elements in the array.
Size = Emit(length, 0);
- Size = CastToUIntType(Size, Size->getType());
} else {
// Compute the variable's size in bytes.
- Size = CastToUIntType(Emit(DECL_SIZE_UNIT(decl), 0), Type::Int32Ty);
+ Size = Emit(DECL_SIZE_UNIT(decl), 0);
Ty = Type::Int8Ty;
}
+ Size = CastToUIntType(Size, Type::Int32Ty);
}
const char *Name; // Name of variable
@@ -4645,94 +4676,71 @@
}
LValue TreeToLLVM::EmitLV_ARRAY_REF(tree exp) {
+ // The result type is an ElementTy* in the case of an ARRAY_REF, an array
+ // of ElementTy in the case of ARRAY_RANGE_REF.
+
tree Array = TREE_OPERAND(exp, 0);
+ tree ArrayType = TREE_TYPE(Array);
tree Index = TREE_OPERAND(exp, 1);
- assert((TREE_CODE (TREE_TYPE(Array)) == ARRAY_TYPE ||
- TREE_CODE (TREE_TYPE(Array)) == POINTER_TYPE ||
- TREE_CODE (TREE_TYPE(Array)) == REFERENCE_TYPE) &&
+ tree IndexType = TREE_TYPE(Index);
+ tree ElementType = TREE_TYPE(ArrayType);
+
+ assert((TREE_CODE (ArrayType) == ARRAY_TYPE ||
+ TREE_CODE (ArrayType) == POINTER_TYPE ||
+ TREE_CODE (ArrayType) == REFERENCE_TYPE) &&
"Unknown ARRAY_REF!");
-
+
// As an LLVM extension, we allow ARRAY_REF with a pointer as the first
// operand. This construct maps directly to a getelementptr instruction.
Value *ArrayAddr;
-
- if (TREE_CODE(TREE_TYPE(Array)) == ARRAY_TYPE) {
+
+ if (TREE_CODE(ArrayType) == ARRAY_TYPE) {
// First subtract the lower bound, if any, in the type of the index.
tree LowerBound = array_ref_low_bound(exp);
if (!integer_zerop(LowerBound))
- Index = fold(build2(MINUS_EXPR, TREE_TYPE(Index), Index, LowerBound));
-
+ Index = fold(build2(MINUS_EXPR, IndexType, Index, LowerBound));
+
LValue ArrayAddrLV = EmitLV(Array);
assert(!ArrayAddrLV.isBitfield() && "Arrays cannot be bitfields!");
ArrayAddr = ArrayAddrLV.Ptr;
} else {
ArrayAddr = Emit(Array, 0);
}
-
+
Value *IndexVal = Emit(Index, 0);
- // FIXME: If UnitSize is a variable, or if it disagrees with the LLVM array
- // element type, insert explicit pointer arithmetic here.
- //tree ElementSizeInBytes = array_ref_element_size(exp);
-
const Type *IntPtrTy = getTargetData().getIntPtrType();
- if (IndexVal->getType() != IntPtrTy) {
- if (TYPE_UNSIGNED(TREE_TYPE(Index))) // if the index is unsigned
- // ZExt it to retain its value in the larger type
- IndexVal = CastToUIntType(IndexVal, IntPtrTy);
- else
- // SExt it to retain its value in the larger type
- IndexVal = CastToSIntType(IndexVal, IntPtrTy);
- }
+ if (TYPE_UNSIGNED(IndexType)) // if the index is unsigned
+ // ZExt it to retain its value in the larger type
+ IndexVal = CastToUIntType(IndexVal, IntPtrTy);
+ else
+ // SExt it to retain its value in the larger type
+ IndexVal = CastToSIntType(IndexVal, IntPtrTy);
- // If this is an index into an array, codegen as a GEP.
- if (TREE_CODE(TREE_TYPE(Array)) == ARRAY_TYPE) {
- Value *Ptr;
-
- // Check for variable sized array reference.
- tree length = arrayLength(TREE_TYPE(Array));
- if (length && !host_integerp(length, 1)) {
- // Make sure that ArrayAddr is of type ElementTy*, then do a 2-index gep.
- ArrayAddr = BitCastToType(ArrayAddr, PointerType::get(Type::Int8Ty));
- Value *Scale = Emit(array_ref_element_size(exp), 0);
- if (Scale->getType() != IntPtrTy)
- Scale = CastToUIntType(Scale, IntPtrTy);
-
- IndexVal = BinaryOperator::createMul(IndexVal, Scale, "tmp", CurBB);
- Ptr = new GetElementPtrInst(ArrayAddr, IndexVal, "tmp", CurBB);
- } else {
- // Otherwise, this is not a variable-sized array, use a GEP to index.
- Ptr = new GetElementPtrInst(ArrayAddr, ConstantInt::get(Type::Int32Ty, 0),
- IndexVal, "tmp", CurBB);
- }
-
- // The result type is an ElementTy* in the case of an ARRAY_REF, an array
- // of ElementTy in the case of ARRAY_RANGE_REF. Return the correct type.
+ // If this is an index into an LLVM array, codegen as a GEP.
+ if (isArrayCompatible(ArrayType)) {
+ Value *Ptr = new GetElementPtrInst(ArrayAddr,
+ ConstantInt::get(Type::Int32Ty, 0),
+ IndexVal, "tmp", CurBB);
return BitCastToType(Ptr, PointerType::get(ConvertType(TREE_TYPE(exp))));
}
- // Otherwise, this is an index off a pointer, codegen as a 2-idx GEP.
- assert(TREE_CODE(TREE_TYPE(Array)) == POINTER_TYPE ||
- TREE_CODE(TREE_TYPE(Array)) == REFERENCE_TYPE);
- tree IndexedType = TREE_TYPE(TREE_TYPE(Array));
-
// If we are indexing over a fixed-size type, just use a GEP.
- if (TREE_CODE(TYPE_SIZE(IndexedType)) == INTEGER_CST) {
- const Type *PtrIndexedTy = PointerType::get(ConvertType(IndexedType));
- ArrayAddr = BitCastToType(ArrayAddr, PtrIndexedTy);
- return new GetElementPtrInst(ArrayAddr, IndexVal, "tmp", CurBB);
+ if (isSequentialCompatible(ArrayType)) {
+ const Type *PtrElementTy = PointerType::get(ConvertType(ElementType));
+ ArrayAddr = BitCastToType(ArrayAddr, PtrElementTy);
+ Value *Ptr = new GetElementPtrInst(ArrayAddr, IndexVal, "tmp", CurBB);
+ return BitCastToType(Ptr, PointerType::get(ConvertType(TREE_TYPE(exp))));
}
-
+
// Otherwise, just do raw, low-level pointer arithmetic. FIXME: this could be
// much nicer in cases like:
// float foo(int w, float A[][w], int g) { return A[g][0]; }
-
+
ArrayAddr = BitCastToType(ArrayAddr, PointerType::get(Type::Int8Ty));
Value *TypeSize = Emit(array_ref_element_size(exp), 0);
+ TypeSize = CastToUIntType(TypeSize, IntPtrTy);
- if (TypeSize->getType() != IntPtrTy)
- TypeSize = CastToUIntType(TypeSize, IntPtrTy);
-
IndexVal = BinaryOperator::createMul(IndexVal, TypeSize, "tmp", CurBB);
Value *Ptr = new GetElementPtrInst(ArrayAddr, IndexVal, "tmp", CurBB);
@@ -5790,44 +5798,41 @@
Constant *TreeConstantToLLVM::EmitLV_ARRAY_REF(tree exp) {
tree Array = TREE_OPERAND(exp, 0);
+ tree ArrayType = TREE_TYPE(Array);
tree Index = TREE_OPERAND(exp, 1);
- assert((TREE_CODE (TREE_TYPE(Array)) == ARRAY_TYPE ||
- TREE_CODE (TREE_TYPE(Array)) == POINTER_TYPE ||
- TREE_CODE (TREE_TYPE(Array)) == REFERENCE_TYPE) &&
+ tree IndexType = TREE_TYPE(Index);
+ assert((TREE_CODE (ArrayType) == ARRAY_TYPE ||
+ TREE_CODE (ArrayType) == POINTER_TYPE ||
+ TREE_CODE (ArrayType) == REFERENCE_TYPE) &&
"Unknown ARRAY_REF!");
-
+
+ // Check for variable sized reference.
+ // FIXME: add support for array types where the size doesn't fit into 64 bits
+ assert(isArrayCompatible(ArrayType) || isSequentialCompatible(ArrayType)
+ && "Cannot have globals with variable size!");
+
// As an LLVM extension, we allow ARRAY_REF with a pointer as the first
// operand. This construct maps directly to a getelementptr instruction.
Constant *ArrayAddr;
- if (TREE_CODE (TREE_TYPE(Array)) == ARRAY_TYPE) {
+ if (TREE_CODE (ArrayType) == ARRAY_TYPE) {
// First subtract the lower bound, if any, in the type of the index.
tree LowerBound = array_ref_low_bound(exp);
if (!integer_zerop(LowerBound))
- Index = fold(build2(MINUS_EXPR, TREE_TYPE(Index), Index, LowerBound));
+ Index = fold(build2(MINUS_EXPR, IndexType, Index, LowerBound));
ArrayAddr = EmitLV(Array);
} else {
ArrayAddr = Convert(Array);
}
Constant *IndexVal = Convert(Index);
-
- // FIXME: If UnitSize is a variable, or if it disagrees with the LLVM array
- // element type, insert explicit pointer arithmetic here.
- //tree ElementSizeInBytes = array_ref_element_size(exp);
-
- if (IndexVal->getType() != Type::Int32Ty &&
- IndexVal->getType() != Type::Int64Ty)
- IndexVal = ConstantExpr::getSExtOrBitCast(IndexVal, Type::Int64Ty);
-
- // Check for variable sized array reference.
- if (TREE_CODE(TREE_TYPE(Array)) == ARRAY_TYPE) {
- tree length = arrayLength(TREE_TYPE(Array));
- assert(!length || host_integerp(length, 1) &&
- "Cannot have globals with variable size!");
- }
+ const Type *IntPtrTy = getTargetData().getIntPtrType();
+ if (IndexVal->getType() != IntPtrTy)
+ IndexVal = ConstantExpr::getIntegerCast(IndexVal, IntPtrTy,
+ !TYPE_UNSIGNED(IndexType));
+
std::vector<Value*> Idx;
- if (TREE_CODE (TREE_TYPE(Array)) == ARRAY_TYPE)
+ if (isArrayCompatible(ArrayType))
Idx.push_back(ConstantInt::get(Type::Int32Ty, 0));
Idx.push_back(IndexVal);
return ConstantExpr::getGetElementPtr(ArrayAddr, &Idx[0], Idx.size());
Modified: apple-local/branches/llvm/gcc/llvm-debug.cpp
===================================================================
--- apple-local/branches/llvm/gcc/llvm-debug.cpp 2007-04-16 18:55:33 UTC (rev 126209)
+++ apple-local/branches/llvm/gcc/llvm-debug.cpp 2007-04-16 20:01:41 UTC (rev 126210)
@@ -582,8 +582,6 @@
tree MinValue = TYPE_MIN_VALUE(Domain);
tree MaxValue = TYPE_MAX_VALUE(Domain);
if (MinValue && MaxValue &&
- TREE_CODE(MinValue) == INTEGER_CST &&
- TREE_CODE(MaxValue) == INTEGER_CST &&
host_integerp(MinValue, 0) &&
host_integerp(MaxValue, 0)) {
Subrange->setLo(tree_low_cst(MinValue, 0));
Modified: apple-local/branches/llvm/gcc/llvm-internal.h
===================================================================
--- apple-local/branches/llvm/gcc/llvm-internal.h 2007-04-16 18:55:33 UTC (rev 126209)
+++ apple-local/branches/llvm/gcc/llvm-internal.h 2007-04-16 20:01:41 UTC (rev 126210)
@@ -144,11 +144,32 @@
return TheTypeConverter->ConvertType(type);
}
+/// isInt64 - Return true if t is an INTEGER_CST that fits in a 64 bit integer.
+/// If Unsigned is false, returns whether it fits in a int64_t. If Unsigned is
+/// true, returns whether the value is non-negative and fits in a uint64_t.
+/// Always returns false for overflowed constants.
+bool isInt64(tree_node *t, bool Unsigned);
+
+/// getInt64 - Extract the value of an INTEGER_CST as a 64 bit integer. If
+/// Unsigned is false, the value must fit in a int64_t. If Unsigned is true,
+/// the value must be non-negative and fit in a uint64_t. Must not be used on
+/// overflowed constants. These conditions can be checked by calling isInt64.
+uint64_t getInt64(tree_node *t, bool Unsigned);
+
/// isPassedByInvisibleReference - Return true if the specified type should be
/// passed by 'invisible reference'. In other words, instead of passing the
/// thing by value, pass the address of a temporary.
bool isPassedByInvisibleReference(tree_node *type);
+/// isSequentialCompatible - Return true if the specified gcc array or pointer
+/// type and the corresponding LLVM SequentialType lay out their components
+/// identically in memory.
+bool isSequentialCompatible(tree_node *type);
+
+/// isArrayCompatible - Return true if the specified gcc array or pointer type
+/// corresponds to an LLVM array type.
+bool isArrayCompatible(tree_node *type);
+
/// arrayLength - Return a tree expressing the number of elements in an array
/// of the specified type, or NULL if the type does not specify the length.
tree_node *arrayLength(tree_node *type);
Modified: apple-local/branches/llvm/gcc/llvm-types.cpp
===================================================================
--- apple-local/branches/llvm/gcc/llvm-types.cpp 2007-04-16 18:55:33 UTC (rev 126209)
+++ apple-local/branches/llvm/gcc/llvm-types.cpp 2007-04-16 20:01:41 UTC (rev 126210)
@@ -73,6 +73,10 @@
// Note down LLVM type for GCC tree node.
static const Type * llvm_set_type(tree Tr, const Type *Ty) {
+ assert(!TYPE_SIZE(Tr) || !Ty->isSized() || !isInt64(TYPE_SIZE(Tr), true) ||
+ getInt64(TYPE_SIZE(Tr), true) == getTargetData().getTypeSizeInBits(Ty)
+ && "LLVM type size doesn't match GCC type size!");
+
unsigned &TypeSlot = LTypesMap[Ty];
if (TypeSlot) {
// Already in map.
@@ -273,6 +277,39 @@
return Prefix + ContextStr + Name;
}
+/// isSequentialCompatible - Return true if the specified gcc array or pointer
+/// type and the corresponding LLVM SequentialType lay out their components
+/// identically in memory.
+bool isSequentialCompatible(tree_node *type) {
+ assert((TREE_CODE (type) == ARRAY_TYPE ||
+ TREE_CODE (type) == POINTER_TYPE ||
+ TREE_CODE (type) == REFERENCE_TYPE) && "not a sequential type!");
+ // This relies on gcc types with constant size mapping to LLVM types with the
+ // same size.
+ return isInt64(TYPE_SIZE(TREE_TYPE(type)), true);
+}
+
+/// isArrayCompatible - Return true if the specified gcc array or pointer type
+/// corresponds to an LLVM array type.
+bool isArrayCompatible(tree_node *type) {
+ assert((TREE_CODE (type) == ARRAY_TYPE ||
+ TREE_CODE (type) == POINTER_TYPE ||
+ TREE_CODE (type) == REFERENCE_TYPE) && "not a sequential type!");
+ return
+ (TREE_CODE (type) == ARRAY_TYPE) && (
+ // Arrays with no size are fine as long as their components are layed out
+ // the same way in memory by LLVM. For example "int X[]" -> "[0 x int]".
+ (!TYPE_SIZE(type) && isSequentialCompatible(type)) ||
+
+ // Arrays with constant size map to LLVM arrays. If the array has zero
+ // size then there can be two exotic cases: (1) the array might have zero
+ // length and a component type of variable size; or (2) the array could
+ // have variable length and a component type with zero size. In both
+ // cases we convert to a zero length LLVM array.
+ (TYPE_SIZE(type) && isInt64(TYPE_SIZE(type), true))
+ );
+}
+
/// arrayLength - Return a tree expressing the number of elements in an array
/// of the specified type, or NULL if the type does not specify the length.
tree_node *arrayLength(tree_node *type) {
@@ -582,30 +619,37 @@
if (const Type *Ty = GET_TYPE_LLVM(type))
return Ty;
- unsigned NumElements;
- tree length = arrayLength(type);
- if (length) {
- if (host_integerp(length, 1)) {
+ if (isArrayCompatible(type)) {
+ uint64_t NumElements;
+ tree length = arrayLength(type);
+
+ if (!length) {
+ // We get here if we have something that is globally declared as an
+ // array with no dimension, this becomes just a zero size array of the
+ // element type so that: int X[] becomes *'%X = external global [0 x int]'
+ //
+ // Note that this also affects new expressions, which return a pointer to
+ // an unsized array of elements.
+ NumElements = 0;
+ } else if (!isInt64(length, true)) {
+ // A variable length array where the element type has size zero. Turn
+ // it into a zero length array of the element type.
+ assert(integer_zerop(TYPE_SIZE(TREE_TYPE(type)))
+ && "variable length array has constant size!");
+ NumElements = 0;
+ } else {
// Normal array.
- NumElements = tree_low_cst(length, 1);
- } else {
- // This handles cases like "int A[n]" which have a runtime constant
- // number of elements, but is a compile-time variable. Since these are
- // variable sized, we just represent them as the element themself.
- return TypeDB.setType(type, ConvertType(TREE_TYPE(type)));
+ NumElements = getInt64(length, true);
}
- } else {
- // We get here is if they have something that is globally declared as an
- // array with no dimension, this becomes just a zero size array of the
- // element type so that: int X[] becomes *'%X = external global [0 x int]'
- //
- // Note that this also affects new expressions, which return a pointer to
- // an unsized array of elements.
- NumElements = 0;
+
+ return TypeDB.setType(type, ArrayType::get(ConvertType(TREE_TYPE(type)),
+ NumElements));
}
-
- return TypeDB.setType(type, ArrayType::get(ConvertType(TREE_TYPE(type)),
- NumElements));
+
+ // This handles cases like "int A[n]" which have a runtime constant
+ // number of elements, but is a compile-time variable. Since these are
+ // variable sized, we just represent them as the element themself.
+ return TypeDB.setType(type, ConvertType(TREE_TYPE(type)));
}
case OFFSET_TYPE:
// Handle OFFSET_TYPE specially. This is used for pointers to members,
More information about the llvm-commits
mailing list