Ada arrays need not be indexed from zero: the indexing can
start from any number, positive or negative.  While some
parts of llvm-gcc had support for non-zero lower bounds,
not everywhere did.  This patch adds consistent support
everywhere.  Also, it considers an array to have dynamic
size if the length is not constant, rather than when the
maximum index is not constant, which is the current test.
Thus an array with index range n..n+4 is considered to
have length 5, a constant [*].  This notion of array size
is also used consistently everywhere.

The impact on non-Ada code should be insignificant.
The potential additional costs come from: (1) converting
array bounds to sizetype; (2) having gcc subtract off
the lower bound; and (3) having gcc add one.  In C it
seems that array bounds are already of type sizetype
(I added an assert and it didn't trigger when building
the C compiler); fold_convert instantly exits in this
case, so the cost of (1) is infinitesimal.  In C the
lower bound is always 0; size_binop does a quick
return in this case, so the cost of (2) is also
infinitesimal.  For C, (3) involves adding one to a
constant, which does not involve any heavy operations
like memory allocation, just a two word integer plus
operation.  So this can also be considered to be zero.

The attachment array_test.diff adds an LLVM testcase
to test/AdaFrontend.  This is currently useless since
the Ada compiler does not build.  There is also no LLVM
build support for test/AdaFrontend yet.

Best wishes,

Duncan.

[*] this optimization is currently of no benefit to
the Ada compiler: it generates n..max(n-1,n+4) as
the array bounds.  Fold fails to simplify max(n-1,n+4)
to n+4 for obscure reasons which I am looking into
(a fold guru tells me it is supposed to work).
Index: gcc.llvm.master/gcc/llvm-convert.cpp
===================================================================
--- gcc.llvm.master.orig/gcc/llvm-convert.cpp	2007-02-28 12:01:19.000000000 +0100
+++ gcc.llvm.master/gcc/llvm-convert.cpp	2007-02-28 18:34:07.000000000 +0100
@@ -1329,18 +1329,14 @@
     DECL_USER_ALIGN(decl) = 0;
     Alignment = DECL_ALIGN(decl)/8;
   } else {
+    tree length;
+
     // Dynamic-size object: must push space on the stack.
-    if (TREE_CODE(type) == ARRAY_TYPE && TYPE_DOMAIN(type)) {
+    if (TREE_CODE(type) == ARRAY_TYPE && (length = arrayLength(type))) {
       Ty = ConvertType(TREE_TYPE(type));  // Get array element type.
-      // Compute the size of the number of elements of the array.
-      Size = Emit(TYPE_MAX_VALUE(TYPE_DOMAIN(type)), 0);
-      Size = CastToUIntType(Size, Type::Int32Ty);
-      
-      // Annoyingly, TYPE_MAX_VALUE returns the maximum valid index, NOT the
-      // number of elements in the array.  Thus, we must add one to the returned
-      // value.  This addition should be optimized out later.
-      Size = BinaryOperator::createAdd(Size, ConstantInt::get(Type::Int32Ty, 1),
-                                       "tmp", CurBB);
+      // 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);
@@ -4246,9 +4242,8 @@
 
   // Check for variable sized array reference.
   if (TREE_CODE(TREE_TYPE(Array)) == ARRAY_TYPE) {
-    tree Domain = TYPE_DOMAIN(TREE_TYPE(Array));
-    if (Domain && TYPE_MAX_VALUE(Domain) &&
-        TREE_CODE(TYPE_MAX_VALUE(Domain)) != INTEGER_CST) {
+    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.
       tree ElTy = TREE_TYPE(TREE_TYPE(Array));
       // This cast only deals with pointers so BitCast is appropriate
@@ -4668,7 +4663,7 @@
     // If this is a variable sized array type, set the length to Len.
     if (ConstantSize == 0) {
       tree Domain = TYPE_DOMAIN(TREE_TYPE(exp));
-      if (Domain == 0 || TYPE_MAX_VALUE(Domain) == 0) {
+      if (!Domain || !TYPE_MAX_VALUE(Domain)) {
         ConstantSize = Len;
         StrTy = ArrayType::get(ElTy, Len);
       }
@@ -4767,21 +4762,23 @@
   // type indirectly.
   assert(TREE_CODE(TREE_TYPE(exp)) != VECTOR_TYPE &&
          "VECTOR_TYPE's haven't been tested!");
-  
-  // If we have constant lower bound for the range of the type, get it.  */
+
+  // If we have a lower bound for the range of the type, get it.  */
   tree Domain = TYPE_DOMAIN(TREE_TYPE(exp));
-  unsigned MinElement = 0;
-  if (Domain && TYPE_MIN_VALUE(Domain) && 
-      host_integerp(TYPE_MIN_VALUE(Domain), 0))
-    MinElement = tree_low_cst(TYPE_MIN_VALUE(Domain), 0);
-  
+  tree min_element = size_zero_node;
+  if (Domain && TYPE_MIN_VALUE(Domain))
+    min_element = fold_convert(sizetype, TYPE_MIN_VALUE(Domain));
+
   std::vector<Constant*> ResultElts;
   Constant *SomeVal = 0;
   
-  if (Domain && TYPE_MAX_VALUE(Domain) && 
-      host_integerp(TYPE_MAX_VALUE(Domain), 0)) {
-    unsigned MaxElement = tree_low_cst(TYPE_MAX_VALUE(Domain), 0);
-    ResultElts.resize(MaxElement-MinElement+1);
+  if (Domain && TYPE_MAX_VALUE(Domain)) {
+    tree max_element = fold_convert(sizetype, TYPE_MAX_VALUE(Domain));
+    tree size = size_binop (MINUS_EXPR, max_element, min_element);
+    size = size_binop (PLUS_EXPR, size, size_one_node);
+
+    if (host_integerp(size, 1))
+      ResultElts.resize(tree_low_cst(size, 1));
   }
 
   unsigned NextFieldToFill = 0;
@@ -4797,14 +4794,21 @@
     // The first and last field to fill in, inclusive.
     unsigned FieldOffset, FieldLastOffset;
     if (index && TREE_CODE(index) == RANGE_EXPR) {
-      assert(TREE_CODE(TREE_OPERAND(index, 0)) == INTEGER_CST &&
-             TREE_CODE(TREE_OPERAND(index, 1)) == INTEGER_CST &&
+      tree first = fold_convert (sizetype, TREE_OPERAND(index, 0));
+      tree last  = fold_convert (sizetype, TREE_OPERAND(index, 1));
+
+      first = size_binop (MINUS_EXPR, first, min_element);
+      last  = size_binop (MINUS_EXPR, last, min_element);
+
+      assert(host_integerp(first, 1) && host_integerp(last, 1) &&
              "Unknown range_expr!");
-      FieldOffset     = TREE_INT_CST_LOW(TREE_OPERAND(index, 0))-MinElement;
-      FieldLastOffset = TREE_INT_CST_LOW(TREE_OPERAND(index, 1))-MinElement;
+      FieldOffset     = tree_low_cst(first, 1);
+      FieldLastOffset = tree_low_cst(last, 1);
     } else if (index) {
-      assert(TREE_CODE(index) == INTEGER_CST && TREE_INT_CST_HIGH(index) == 0);
-      FieldOffset = TREE_INT_CST_LOW(index)-MinElement;
+      index = size_binop (MINUS_EXPR, fold_convert (sizetype, index),
+                          min_element);
+      assert(host_integerp(index, 1));
+      FieldOffset = tree_low_cst(index, 1);
       FieldLastOffset = FieldOffset;
     } else {
       FieldOffset = NextFieldToFill;
@@ -5314,11 +5318,9 @@
   
   // Check for variable sized array reference.
   if (TREE_CODE(TREE_TYPE(Array)) == ARRAY_TYPE) {
-    tree Domain = TYPE_DOMAIN(TREE_TYPE(Array));
-    if (Domain && TYPE_MAX_VALUE(Domain)) {
-      assert(TREE_CODE(TYPE_MAX_VALUE(Domain)) == INTEGER_CST &&
-             "Cannot have globals with variable size!");
-    }
+    tree length = arrayLength(TREE_TYPE(Array));
+    assert(!length || host_integerp(length, 1) &&
+           "Cannot have globals with variable size!");
   }
 
   std::vector<Value*> Idx;
Index: gcc.llvm.master/gcc/llvm-types.cpp
===================================================================
--- gcc.llvm.master.orig/gcc/llvm-types.cpp	2007-02-28 12:10:33.000000000 +0100
+++ gcc.llvm.master/gcc/llvm-types.cpp	2007-02-28 18:07:15.000000000 +0100
@@ -280,6 +280,21 @@
   }
 }
 
+/// 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) {
+  tree Domain = TYPE_DOMAIN(type);
+
+  if (!Domain || !TYPE_MAX_VALUE(Domain))
+    return NULL;
+
+  tree length = fold_convert(sizetype, TYPE_MAX_VALUE(Domain));
+  if (TYPE_MIN_VALUE(Domain))
+    length = size_binop (MINUS_EXPR, length,
+                         fold_convert(sizetype, TYPE_MIN_VALUE(Domain)));
+  return size_binop (PLUS_EXPR, length, size_one_node);
+}
+
 
 //===----------------------------------------------------------------------===//
 //                     Abstract Type Refinement Helpers
@@ -577,11 +592,11 @@
       return Ty;
 
     unsigned NumElements;
-    tree Domain = TYPE_DOMAIN(type);
-    if (Domain && TYPE_MAX_VALUE(Domain)) {
-      if (TREE_CODE(TYPE_MAX_VALUE(Domain)) == INTEGER_CST) {
+    tree length = arrayLength(type);
+    if (length) {
+      if (host_integerp(length, 1)) {
         // Normal array.
-        NumElements = TREE_INT_CST_LOW(TYPE_MAX_VALUE(Domain))+1;
+        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
Index: gcc.llvm.master/gcc/llvm-abi.h
===================================================================
--- gcc.llvm.master.orig/gcc/llvm-abi.h	2007-02-28 12:01:19.000000000 +0100
+++ gcc.llvm.master/gcc/llvm-abi.h	2007-02-28 18:07:14.000000000 +0100
@@ -109,15 +109,10 @@
       }
     return FoundField ? isSingleElementStructOrArray(FoundField) : 0;
   case ARRAY_TYPE:
-    tree Domain = TYPE_DOMAIN(type);
-    if (!Domain || !TYPE_MIN_VALUE(Domain) || !TYPE_MAX_VALUE(Domain))
+    if (TREE_CODE(TYPE_SIZE(type)) != INTEGER_CST)
       return 0;
-    if (TREE_CODE(TYPE_SIZE(type)) != INTEGER_CST ||
-        TREE_CODE(TYPE_MIN_VALUE(Domain)) != INTEGER_CST ||
-        TREE_CODE(TYPE_MAX_VALUE(Domain)) != INTEGER_CST)
-      return 0;
-    if (TREE_INT_CST_LOW(TYPE_MAX_VALUE(Domain)) !=
-        TREE_INT_CST_LOW(TYPE_MIN_VALUE(Domain)))
+    tree length = arrayLength(type);
+    if (!length || !integer_onep(length))
       return 0;
     return isSingleElementStructOrArray(TREE_TYPE(type));
   }
Index: gcc.llvm.master/gcc/llvm-internal.h
===================================================================
--- gcc.llvm.master.orig/gcc/llvm-internal.h	2007-02-28 12:01:19.000000000 +0100
+++ gcc.llvm.master/gcc/llvm-internal.h	2007-02-28 12:10:38.000000000 +0100
@@ -148,6 +148,10 @@
 /// thing by value, pass the address of a temporary.
 bool isPassedByInvisibleReference(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);
+
 /// ValidateRegisterVariable - Check that a static "asm" variable is
 /// well-formed.  If not, emit error messages and return true.  If so, return
 /// false.
Index: llvm/test/AdaFrontend/array_constructor.adb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ llvm/test/AdaFrontend/array_constructor.adb	2007-02-28 18:04:52.000000000 +0100
@@ -0,0 +1,6 @@
+-- RUN: %llvmgcc -c %s -o /dev/null
+procedure Array_Constructor is
+   A : array (Integer range <>) of Boolean := (True, False);
+begin
+   null;
+end;
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

Reply via email to