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