In gcc, the length of an array may only be known at runtime, for
example "char X[n];" is legal; the same goes for array types: the
length of the array type may depend on the value of a variable.
This is a gcc C extension, so somewhat rare, but is widely used in
languages like Ada.  You can construct pointers to such types and
arrays where the element type is such a variable-sized array.  This
is one way of getting an array where the element type does not have
a fixed size; the other way is to use a variable-sized struct as the
element type.  Currently such arrays are handled wrong: loads and
stores to elements (via ARRAY_REF) access the wrong memory location.

The reason for this is simple enough: the gcc element type (EType) and
the corresponding LLVM type (ETypeLLVM) have different sizes.  This means
that LLVM arrays of the LLVM element type lay their components out in
memory differently to the gcc array.  For example, suppose the element
type EType is "char [n]", a length n string, and the array type AType is
an array of three ETypes, which I'll write as "(char [n])[3]".

Right now these get converted as follows:

GCC             LLVM
char[n]         i8
(char [n])[3]   [3 x i8]

GCC memory layout
element: 0 0      0  1  1       1    2      2
   byte: 0 1 ... n-1 n n+1 ... 2n-1 2n .. 3n-1

LLVM memory layout
element: 0 1 2
   byte: 0 1 2

Referencing element 1 accesses 1 byte from the start when it should be
accessing the n'th byte from the start.  The testcase shows an example
of the bogus results this can give (2007-03-27-ArrayCompatible.c).

The conversion to an LLVM array is clearly bogus.  There is an analogous
problem with pointers: using GetElementPtr to do pointer offsets is only
valid if the LLVM type is the same size as the GCC type, since otherwise
the pointer will be advanced by the wrong amount.

The patch introduces utility functions isSequentialCompatible and
isArrayCompatible that apply to a gcc array (or pointer type).  If
isSequentialCompatible returns true, then elements of the gcc type
are laid out in memory the same as the corresponding LLVM elements.
Thus GetElementPtr can be used to access them.  If isArrayCompatible
returns true, then the gcc array corresponds to an LLVM array,
laying out its components the same way.

isSequentialCompatible relies on the following invariant: if the size
of a gcc type is a constant, then the corresponding LLVM type has the
same size [1].  I've added an assertion in llvm-types to check that this
is true.  isSequentialCompatible simply returns whether the gcc element
type has constant size [1].  Thus isSequentialCompatible returns true for
a variable length array with a constant size element type.

isArrayCompatible returns true if the array has a constant length and the
element type has constant size [2].

The patch then fixes up a bunch of array code to use these.  It also
modifies pointer code to use isSequentialCompatible, but these modifications
are minor since the pointer code already got it right.

For example, both isSequentialCompatible and isArrayCompatible return
false for the array type example described above.  The conversions are
now:

GCC             LLVM
char[n]         i8
(char [n])[3]   i8

and the LLVM memory layout is done using pointer arithmetic.

The patch also introduces two generally useful methods requested by Chris:
isInt64 and getInt64.  These tell you whether a gcc constant fits into 64
bits, and gets the constant for you (aborting if it doesn't fit).  They are
analogous to host_integerp and tree_low_cst, only using 64 bit integers rather
than HOST_WIDE_INT.  They are used for example to tell whether the size in
bits of the gcc type is small enough (< 2^64) to correspond to an LLVM type [3].
The main difference with getINTEGER_CSTVal is that getInt64 refuses to return
constants that overflowed or are simply too big for 64 bits.

I corrected a number of other small problems while I was there:

- I unified the pointer and array cases in TreeToLLVM::EmitLV_ARRAY_REF.  The
pointer code did a better job than the array code and the array code benefits
from this: indexing into a variable length array with a constant size element
type (i.e. when isSequentialCompatible is true) now uses a GetElementPtr rather
than 'orrible pointer arithmetic.  This produces vastly better code when, for
example, accessing elements of an array like "int X[n]".  There's a testcase
for this (2007-03-27-VarLengthArray.c).

- The size passed to an AllocaInst might not be an Int32.  Probably impossible
to hit in practice.

- If the index type in TreeConstantToLLVM::EmitLV_ARRAY_REF was an unsigned
32 bit integer, you could get wrong code on a 64 bit machine.  Wildly unlikely
it could ever be hit.

Bootstraps, causes no testsuite failures (including multisource) and indeed
on my system causes 2003-05-22-VarSizeArray.c to pass rather than crash the
gcc 4.1 compiler (CBE) because the improved array indexing causes the testcase
to be simplified down to one line: ret i32 0.

Enjoy!

Duncan.

[1] To be exact, the invariant is: if the size of the gcc type in bits
is a non-negative constant smaller than 2^64 then the LLVM type has the
same size in bits.

[2] It also returns true if the array has no length and the element type
has constant size, like "int X[];".  In order to preserve the invariant
described in [1], it has to return true if the gcc array type has constant
size, which means that variable length arrays with an element type of zero
size and zero length arrays with a variable size element type are both
accepted; they have size zero and so does the corresponding LLVM array.

[3] It is easy to create huge types, for example an array of 2^64 arrays
of length 2^64.  This will not map to an LLVM type.  It is huge objects
that are hard to create.
Index: gcc.llvm/gcc/llvm-abi.h
===================================================================
--- gcc.llvm.orig/gcc/llvm-abi.h	2007-03-20 16:04:45.000000000 +0100
+++ gcc.llvm/gcc/llvm-abi.h	2007-03-28 14:37:26.000000000 +0200
@@ -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))
Index: gcc.llvm/gcc/llvm-convert.cpp
===================================================================
--- gcc.llvm.orig/gcc/llvm-convert.cpp	2007-03-27 14:51:00.000000000 +0200
+++ gcc.llvm/gcc/llvm-convert.cpp	2007-03-28 14:37:26.000000000 +0200
@@ -236,6 +236,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 ...
 //===----------------------------------------------------------------------===//
@@ -1356,16 +1385,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
@@ -4544,94 +4575,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 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);
-    }
+  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);
 
-    // 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);
 
@@ -5670,44 +5678,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());
Index: gcc.llvm/gcc/llvm-debug.cpp
===================================================================
--- gcc.llvm.orig/gcc/llvm-debug.cpp	2007-02-18 19:21:10.000000000 +0100
+++ gcc.llvm/gcc/llvm-debug.cpp	2007-03-28 14:37:26.000000000 +0200
@@ -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));
Index: gcc.llvm/gcc/llvm-internal.h
===================================================================
--- gcc.llvm.orig/gcc/llvm-internal.h	2007-03-20 16:04:45.000000000 +0100
+++ gcc.llvm/gcc/llvm-internal.h	2007-03-28 14:37:26.000000000 +0200
@@ -143,11 +143,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);
Index: gcc.llvm/gcc/llvm-types.cpp
===================================================================
--- gcc.llvm.orig/gcc/llvm-types.cpp	2007-03-27 14:51:00.000000000 +0200
+++ gcc.llvm/gcc/llvm-types.cpp	2007-03-28 14:37:26.000000000 +0200
@@ -72,6 +72,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.
@@ -272,6 +276,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) {
@@ -581,30 +618,37 @@
     if (const Type *Ty = GET_TYPE_LLVM(type))
       return Ty;
 
-    unsigned NumElements;
-    tree length = arrayLength(type);
-    if (length) {
-      if (host_integerp(length, 1)) {
-        // Normal array.
-        NumElements = tree_low_cst(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 {
-        // 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)));
+        // Normal array.
+        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,
// RUN: %llvmgcc -S %s -O2 -o - | grep "ret i8 0"
static char c(int n) {
  char x[2][n];
  x[1][0]=0;
  return *(n+(char *)x);
}

char d(void) {
  return c(2);
}
// RUN: %llvmgcc -S %s -o - | grep 'getelementptr i32'
extern void f(int *);
int e(int m, int n) {
  int x[n];
  f(x);
  return x[m];
}
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

Reply via email to