tree-optimization/110702 - avoid zero-based memory references in IVOPTs

Sometimes IVOPTs chooses a weird induction variable which downstream
leads to issues.  Most of the times we can fend those off during costing
by rejecting the candidate but it looks like the address description
costing synthesizes is different from what we end up generating so
the following fixes things up at code generation time.  Specifically
we avoid the create_mem_ref_raw fallback which uses a literal zero
address base with the actual base in index2.  For the case in question
we have the address

  type = unsigned long
  offset = 0
  elements = {
    [0] = &e * -3,
    [1] = (sizetype) a.9_30 * 232,
    [2] = ivtmp.28_44 * 4
  }

from which we code generate the problematical

  _3 = MEM[(long int *)0B + ivtmp.36_9 + ivtmp.28_44 * 4];

which references the object at address zero.  The patch below
recognizes the fallback after the fact and transforms the
TARGET_MEM_REF memory reference into a LEA for which this form
isn't problematic:

  _24 = &MEM[(long int *)0B + ivtmp.36_34 + ivtmp.28_44 * 4];
  _3 = *_24;

hereby avoiding the correctness issue.  We'd later conclude the
program terminates at the null pointer dereference and make the
function pure, miscompling the main function of the testcase.

	PR tree-optimization/110702
	* tree-ssa-loop-ivopts.cc (rewrite_use_address): When
	we created a NULL pointer based access rewrite that to
	a LEA.

	* gcc.dg/torture/pr110702.c: New testcase.

(cherry picked from commit 13dfb01e5c)
This commit is contained in:
Richard Biener 2023-08-03 13:11:12 +02:00
parent 34bb7282da
commit 56d6989705
2 changed files with 47 additions and 1 deletions

View File

@ -0,0 +1,31 @@
/* { dg-do run } */
void abort (void);
int a, b, c, d;
long e[9][7][4];
void f()
{
for (; a >= 0; a--)
{
b = 0;
for (; b <= 3; b++)
{
c = 0;
for (; c <= 3; c++)
{
int *g = &d;
*g = e[0][0][b] | e[a][b][a];
}
}
}
}
int main()
{
f();
if (a != -1)
abort ();
return 0;
}

View File

@ -7616,7 +7616,22 @@ rewrite_use_address (struct ivopts_data *data,
true, GSI_SAME_STMT);
}
else
copy_ref_info (ref, *use->op_p);
{
/* When we end up confused enough and have no suitable base but
stuffed everything to index2 use a LEA for the address and
create a plain MEM_REF to avoid basing a memory reference
on address zero which create_mem_ref_raw does as fallback. */
if (TREE_CODE (ref) == TARGET_MEM_REF
&& TMR_INDEX2 (ref) != NULL_TREE
&& integer_zerop (TREE_OPERAND (ref, 0)))
{
ref = fold_build1 (ADDR_EXPR, TREE_TYPE (TREE_OPERAND (ref, 0)), ref);
ref = force_gimple_operand_gsi (&bsi, ref, true, NULL_TREE,
true, GSI_SAME_STMT);
ref = build2 (MEM_REF, type, ref, build_zero_cst (alias_ptr_type));
}
copy_ref_info (ref, *use->op_p);
}
*use->op_p = ref;
}