From e287a2a11d7958e5d9f7c6172e59cc83495e393a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 22 Jan 2021 11:42:03 +0100 Subject: [PATCH] on ARRAY_REFs sign-extend offsets only from sizetype's precision [PR98255] As discussed in the PR, the problem here is that the routines changed in this patch sign extend the difference of index and low_bound from the precision of the index, so e.g. when index is unsigned int and contains value -2U, we treat it as index -2 rather than 0x00000000fffffffeU on 64-bit arches. On the other hand, get_inner_reference which is used during expansion, does: if (! integer_zerop (low_bound)) index = fold_build2 (MINUS_EXPR, TREE_TYPE (index), index, low_bound); offset = size_binop (PLUS_EXPR, offset, size_binop (MULT_EXPR, fold_convert (sizetype, index), unit_size)); which effectively requires that either low_bound is constant 0 and then index in ARRAY_REFs can be arbitrary type which is then sign or zero extended to sizetype, or low_bound is something else and then index and low_bound must have compatible types and it is still converted afterwards to sizetype and from there then a few lines later: expr.c- if (poly_int_tree_p (offset)) expr.c- { expr.c: poly_offset_int tem = wi::sext (wi::to_poly_offset (offset), expr.c- TYPE_PRECISION (sizetype)); The following patch makes those routines match what get_inner_reference is doing. 2021-01-22 Jakub Jelinek PR tree-optimization/98255 * tree-dfa.c (get_ref_base_and_extent): For ARRAY_REFs, sign extend index - low_bound from sizetype's precision rather than index precision. (get_addr_base_and_unit_offset_1): Likewise. * tree-ssa-sccvn.c (ao_ref_init_from_vn_reference): Likewise. * gimple-fold.c (fold_const_aggregate_ref_1): Likewise. * gcc.dg/pr98255.c: New test. --- gcc/gimple-fold.c | 2 +- gcc/testsuite/gcc.dg/pr98255.c | 49 ++++++++++++++++++++++++++++++++++++++++++ gcc/tree-dfa.c | 6 +++--- gcc/tree-ssa-sccvn.c | 2 +- 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr98255.c diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index fe46d98..de5a6c2 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -8007,7 +8007,7 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree)) poly_offset_int woffset = wi::sext (wi::to_poly_offset (idx) - wi::to_poly_offset (low_bound), - TYPE_PRECISION (TREE_TYPE (idx))); + TYPE_PRECISION (sizetype)); woffset *= tree_to_uhwi (unit_size); woffset *= BITS_PER_UNIT; if (woffset.to_shwi (&offset)) diff --git a/gcc/testsuite/gcc.dg/pr98255.c b/gcc/testsuite/gcc.dg/pr98255.c new file mode 100644 index 0000000..5cbed68 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr98255.c @@ -0,0 +1,49 @@ +/* PR tree-optimization/98255 */ +/* { dg-do run } */ +/* { dg-options "-Os" } */ +/* { dg-additional-options "-fPIC" { target fpic } } */ + +struct A { volatile unsigned b; unsigned c; }; +int d, *e, h, k, l; +static struct A f; +long g; +static unsigned i = -2U; +volatile int j; + +long +foo (void) +{ + char n[4][4][3] + = { { {9, 2, 8}, {9, 2, 8}, {9, 2, 8}, {9} }, { {8} }, { {8} }, { {2} } }; + while (d) + { + for (; f.c < 4; f.c++) + { + *e = 0; + h = n[f.c + 4][0][d]; + } + while (g) + return n[0][3][i]; + while (1) + { + if (k) + { + j = 0; + if (j) + continue; + } + if (l) + break; + } + } + return 0; +} + +int +main () +{ + asm volatile ("" : "+g" (d), "+g" (g), "+g" (f.c)); + asm volatile ("" : "+g" (e), "+g" (k), "+g" (l)); + foo (); + return 0; +} diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index 648fdd0..0482b05 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -503,7 +503,7 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset, poly_offset_int woffset = wi::sext (wi::to_poly_offset (index) - wi::to_poly_offset (low_bound), - TYPE_PRECISION (TREE_TYPE (index))); + TYPE_PRECISION (sizetype)); woffset *= wi::to_offset (unit_size); woffset <<= LOG2_BITS_PER_UNIT; bit_offset += woffset; @@ -564,7 +564,7 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset, { poly_offset_int woffset = wi::sext (omin - lbound, - TYPE_PRECISION (TREE_TYPE (index))); + TYPE_PRECISION (sizetype)); woffset *= wi::to_offset (unit_size); woffset <<= LOG2_BITS_PER_UNIT; bit_offset += woffset; @@ -822,7 +822,7 @@ get_addr_base_and_unit_offset_1 (tree exp, poly_int64_pod *poffset, poly_offset_int woffset = wi::sext (wi::to_poly_offset (index) - wi::to_poly_offset (low_bound), - TYPE_PRECISION (TREE_TYPE (index))); + TYPE_PRECISION (sizetype)); woffset *= wi::to_offset (unit_size); byte_offset += woffset.force_shwi (); } diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 588f1b8..d45aee8 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -1108,7 +1108,7 @@ ao_ref_init_from_vn_reference (ao_ref *ref, poly_offset_int woffset = wi::sext (wi::to_poly_offset (op->op0) - wi::to_poly_offset (op->op1), - TYPE_PRECISION (TREE_TYPE (op->op0))); + TYPE_PRECISION (sizetype)); woffset *= wi::to_offset (op->op2) * vn_ref_op_align_unit (op); woffset <<= LOG2_BITS_PER_UNIT; offset += woffset; -- 2.7.4