diff options
author | Jakub Jelinek <jakub@redhat.com> | 2002-02-21 00:05:47 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2002-02-21 00:05:47 +0100 |
commit | 7552da58e17fb0e2c53a03bd986eee6baea79730 (patch) | |
tree | 61e2d388e4c9e1800d174ed4d1ad82befd143f53 /gcc/c-common.c | |
parent | 00fae85dcb96cb20e723b37ae16dcf1cf09434da (diff) | |
download | gcc-7552da58e17fb0e2c53a03bd986eee6baea79730.zip gcc-7552da58e17fb0e2c53a03bd986eee6baea79730.tar.gz gcc-7552da58e17fb0e2c53a03bd986eee6baea79730.tar.bz2 |
re PR c++/4401 (Array subscript evaluation sometimes wrong for 64-bit architectures)
PR c++/4401
* c-common.c (pointer_int_sum): Moved from...
* c-typeck.c (pointer_int_sum): ...here.
* c-common.h (pointer_int_sum): Add prototype.
* typeck.c (cp_pointer_int_sum): Renamed from
pointer_int_sum, call pointer_int_sum.
* g++.dg/opt/ptrintsum1.C: New test.
From-SVN: r49916
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index b2bdf50..dfdacca 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1982,6 +1982,107 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) return 0; } +/* Return a tree for the sum or difference (RESULTCODE says which) + of pointer PTROP and integer INTOP. */ + +tree +pointer_int_sum (resultcode, ptrop, intop) + enum tree_code resultcode; + tree ptrop, intop; +{ + tree size_exp; + + tree result; + tree folded; + + /* The result is a pointer of the same type that is being added. */ + + tree result_type = TREE_TYPE (ptrop); + + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer of type `void *' used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer to a function used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer to member function used in arithmetic"); + size_exp = integer_one_node; + } + else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE) + { + if (pedantic || warn_pointer_arith) + pedwarn ("pointer to a member used in arithmetic"); + size_exp = integer_one_node; + } + else + size_exp = size_in_bytes (TREE_TYPE (result_type)); + + /* If what we are about to multiply by the size of the elements + contains a constant term, apply distributive law + and multiply that constant term separately. + This helps produce common subexpressions. */ + + if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR) + && ! TREE_CONSTANT (intop) + && TREE_CONSTANT (TREE_OPERAND (intop, 1)) + && TREE_CONSTANT (size_exp) + /* If the constant comes from pointer subtraction, + skip this optimization--it would cause an error. */ + && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE + /* If the constant is unsigned, and smaller than the pointer size, + then we must skip this optimization. This is because it could cause + an overflow error if the constant is negative but INTOP is not. */ + && (! TREE_UNSIGNED (TREE_TYPE (intop)) + || (TYPE_PRECISION (TREE_TYPE (intop)) + == TYPE_PRECISION (TREE_TYPE (ptrop))))) + { + enum tree_code subcode = resultcode; + tree int_type = TREE_TYPE (intop); + if (TREE_CODE (intop) == MINUS_EXPR) + subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); + /* Convert both subexpression types to the type of intop, + because weird cases involving pointer arithmetic + can result in a sum or difference with different type args. */ + ptrop = build_binary_op (subcode, ptrop, + convert (int_type, TREE_OPERAND (intop, 1)), 1); + intop = convert (int_type, TREE_OPERAND (intop, 0)); + } + + /* Convert the integer argument to a type the same size as sizetype + so the multiply won't overflow spuriously. */ + + if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype) + || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype)) + intop = convert (type_for_size (TYPE_PRECISION (sizetype), + TREE_UNSIGNED (sizetype)), intop); + + /* Replace the integer argument with a suitable product by the object size. + Do this multiplication as signed, then convert to the appropriate + pointer type (actually unsigned integral). */ + + intop = convert (result_type, + build_binary_op (MULT_EXPR, intop, + convert (TREE_TYPE (intop), size_exp), 1)); + + /* Create the sum or difference. */ + + result = build (resultcode, result_type, ptrop, intop); + + folded = fold (result); + if (folded == result) + TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop); + return folded; +} + /* Prepare expr to be an argument of a TRUTH_NOT_EXPR, or validate its data type for an `if' or `while' statement or ?..: exp. |