From 7552da58e17fb0e2c53a03bd986eee6baea79730 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 21 Feb 2002 00:05:47 +0100 Subject: [PATCH] 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 --- gcc/ChangeLog | 7 ++ gcc/c-common.c | 101 ++++++++++++++++++++++++++ gcc/c-common.h | 1 + gcc/c-typeck.c | 90 ----------------------- gcc/cp/ChangeLog | 5 ++ gcc/cp/typeck.c | 94 ++---------------------- gcc/testsuite/ChangeLog | 2 + gcc/testsuite/g++.dg/opt/ptrintsum1.C | 29 ++++++++ 8 files changed, 152 insertions(+), 177 deletions(-) create mode 100644 gcc/testsuite/g++.dg/opt/ptrintsum1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b5f5fcd1e9c..59d8288a77a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2002-02-20 Jakub Jelinek + + 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. + 2002-02-20 Jakub Jelinek PR c++/5713 diff --git a/gcc/c-common.c b/gcc/c-common.c index b2bdf50ef28..dfdacca3c55 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. diff --git a/gcc/c-common.h b/gcc/c-common.h index c90cbfb076b..9bb2d1ac233 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -538,6 +538,7 @@ extern char *get_directive_line PARAMS ((void)); and, if so, perhaps change them both back to their original type. */ extern tree shorten_compare PARAMS ((tree *, tree *, tree *, enum tree_code *)); +extern tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); extern unsigned int min_precision PARAMS ((tree, int)); /* Add qualifiers to a type, in the fashion for C. */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index dd8abdd11f7..4ee7cb3b697 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -58,7 +58,6 @@ static tree decl_constant_value_for_broken_optimization PARAMS ((tree)); static tree default_function_array_conversion PARAMS ((tree)); static tree lookup_field PARAMS ((tree, tree)); static tree convert_arguments PARAMS ((tree, tree, tree, tree)); -static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); static tree pointer_diff PARAMS ((tree, tree)); static tree unary_complex_lvalue PARAMS ((enum tree_code, tree, int)); static void pedantic_lvalue_warning PARAMS ((enum tree_code)); @@ -2637,95 +2636,6 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) } } -/* Return a tree for the sum or difference (RESULTCODE says which) - of pointer PTROP and integer INTOP. */ - -static 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 - size_exp = c_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; -} - /* Return a tree for the difference of pointers OP0 and OP1. The resulting tree has type int. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 97591842633..b4a5b0bcf24 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2002-02-20 Jakub Jelinek + + * typeck.c (cp_pointer_int_sum): Renamed from + pointer_int_sum, call pointer_int_sum. + 2002-02-20 Jakub Jelinek * decl.c (duplicate_decls): Return 0 if issued error about diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 62d17a8cfd9..6ca524233d8 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -45,7 +45,7 @@ Boston, MA 02111-1307, USA. */ static tree convert_for_assignment PARAMS ((tree, tree, const char *, tree, int)); -static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); +static tree cp_pointer_int_sum PARAMS ((enum tree_code, tree, tree)); static tree rationalize_conditional_expr PARAMS ((enum tree_code, tree)); static int comp_target_parms PARAMS ((tree, tree)); static int comp_ptr_ttypes_real PARAMS ((tree, tree, int)); @@ -3452,9 +3452,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) case PLUS_EXPR: /* Handle the pointer + int case. */ if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) - return pointer_int_sum (PLUS_EXPR, op0, op1); + return cp_pointer_int_sum (PLUS_EXPR, op0, op1); else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE) - return pointer_int_sum (PLUS_EXPR, op1, op0); + return cp_pointer_int_sum (PLUS_EXPR, op1, op0); else common = 1; break; @@ -3467,7 +3467,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) return pointer_diff (op0, op1, common_type (type0, type1)); /* Handle pointer minus int. Just like pointer plus int. */ else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) - return pointer_int_sum (MINUS_EXPR, op0, op1); + return cp_pointer_int_sum (MINUS_EXPR, op0, op1); else common = 1; break; @@ -4072,94 +4072,14 @@ build_binary_op (code, orig_op0, orig_op1, convert_p) of pointer PTROP and integer INTOP. */ static tree -pointer_int_sum (resultcode, ptrop, intop) +cp_pointer_int_sum (resultcode, ptrop, intop) enum tree_code resultcode; register tree ptrop, intop; { - tree size_exp; - - register tree result; - register tree folded = fold (intop); - - /* The result is a pointer of the same type that is being added. */ - - register tree result_type = TREE_TYPE (ptrop); - - if (!complete_type_or_else (result_type, ptrop)) + if (!complete_type_or_else (TREE_TYPE (ptrop), ptrop)) return error_mark_node; - if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) - { - if (pedantic || warn_pointer_arith) - pedwarn ("ISO C++ forbids using pointer of type `void *' in pointer arithmetic"); - size_exp = integer_one_node; - } - else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE) - { - if (pedantic || warn_pointer_arith) - pedwarn ("ISO C++ forbids using a pointer-to-function in pointer arithmetic"); - size_exp = integer_one_node; - } - else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE) - { - if (pedantic || warn_pointer_arith) - pedwarn ("ISO C++ forbids using a pointer to member function in pointer arithmetic"); - size_exp = integer_one_node; - } - else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE) - { - if (pedantic || warn_pointer_arith) - pedwarn ("ISO C++ forbids using pointer to a member in pointer arithmetic"); - size_exp = integer_one_node; - } - else - size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type))); - - /* Needed to make OOPS V2R3 work. */ - intop = folded; - if (integer_zerop (intop)) - return ptrop; - - /* 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)) - { - enum tree_code subcode = resultcode; - if (TREE_CODE (intop) == MINUS_EXPR) - subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); - ptrop = cp_build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1)); - intop = 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)) - intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), 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 = cp_convert (result_type, - cp_build_binary_op (MULT_EXPR, intop, - cp_convert (TREE_TYPE (intop), - size_exp))); - - /* 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; + return pointer_int_sum (resultcode, ptrop, fold (intop)); } /* Return a tree for the difference of pointers OP0 and OP1. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 65b5ecbb594..ebf920fc0f8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -6,6 +6,8 @@ * gcc.dg/noncompile/20020220-1.c: New test. + * g++.dg/opt/ptrintsum1.C: New test. + 2002-02-17 Jakub Jelinek * gcc.c-torture/execute/20020216-1.c: New test. diff --git a/gcc/testsuite/g++.dg/opt/ptrintsum1.C b/gcc/testsuite/g++.dg/opt/ptrintsum1.C new file mode 100644 index 00000000000..a6a3c9727db --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/ptrintsum1.C @@ -0,0 +1,29 @@ +// PR c++/4401 +// This testcase was miscompiled on 64-bit platforms, resulting to +// operating on a[0x100000000] instead of a[0]. +// { dg-do run } +// { dg-options "-O2" } + +char *a; +char b[] = "AAAA"; + +extern "C" void abort (void); +extern "C" void exit (int); + +void foo (void) +{ + unsigned int i, j; + + i = 2; + j = 3; + a[i + 1 - j] += i; +} + +int main (void) +{ + a = b; + foo (); + if (b[0] != 'A' + 2) + abort (); + exit (0); +} -- 2.30.2