This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Yet another VLA fix
- From: law at redhat dot com
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 07 May 2003 21:01:53 -0600
- Subject: [tree-ssa] Yet another VLA fix
- Reply-to: law at redhat dot com
gcc.dg/20011015-1.c shows another problem with our code which searches
for VLAs.
If you look at the .dce dump for function "baz" you'll find something
like this:
baz (x)
{
{
char * x;
x_2 = x_1;
{
char retval.6;
char T.2;
int T.3;
unsigned int T.4;
unsigned int T.5;
{
char * x;
int <UV1cb0>;
x_3 = x_2;
{
char T.1;
T.1_6 = (*x)_5;
<UV1cb0>_7 = (int)T.1_6;
goto <UL1d90>;
};
<UL1d90>:;;
retval.6_8 = (char)<UV1cb0>_7
};
T.3_9 = (int)retval.6_8;
(void)0;
(void)0;
{
void * arr[T.5];
(void)0
}
}
}
}
Note carefully that T.5 is uninitialized.
This really had me confused for a while as tracing the VLA code showed
that we were marking T.5 as having a hidden use. Hmm, that's odd.
Then I realized that we were marking the *wrong* T.5 -- we marked the
T.5 occurring in function "bar" as having a hidden use. Thus the T.5
in function "baz" appeared unused and it's initialization was removed
by dead code elimination.
When I started looking at the code I was *very* confused as to why we
were looking at the size of the ARRAY_TYPE (which might involve a
SAVE_EXPR referencing variables in another function's context) -- what
we really need to look at is the size of the VAR_DECL!
Changing the code to look at the VAR_DECL's size in the expected manner
resulted in something that looks a lot more sensible:
baz (x)
{
{
char * x;
x_2 = x_1;
{
char retval.6;
int T.3;
unsigned int T.4;
unsigned int T.5;
{
char * x;
int <UV1c40>;
x_3 = x_2;
{
char T.1;
T.1_6 = (*x)_5;
<UV1c40>_7 = (int)T.1_6;
goto <UL1d20>;
};
<UL1d20>:;;
retval.6_8 = (char)<UV1c40>_7
};
T.3_9 = (int)retval.6_8;
T.4_10 = (unsigned int)T.3_9;
T.5_11 = T.4_10 * 4;
{
void * arr[T.5];
(void)0
}
}
}
}
[ Like many of the DFA bugs I've fixed recently, this bug was exposed by
my code which removes unused variables. Damn it's good at finding
broken stuff. ]
* tree-dfa.c (find_hidden_use_vars): Look at the size of
VAR_DECLs, not the size of ARRAY_TYPES. Also make sure
to reset *inside_vla to its original value when done
processing any particular VAR_DECL.
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.107
diff -c -3 -p -r1.1.4.107 tree-dfa.c
*** tree-dfa.c 7 May 2003 13:28:27 -0000 1.1.4.107
--- tree-dfa.c 8 May 2003 02:58:00 -0000
*************** find_hidden_use_vars (block)
*** 2571,2580 ****
return 0;
}
! /* Callback for walk_tree used by find_hidden_use_vars to analyze each array
! in a lexical block. For each array type, it walks its TYPE_SIZE and
! TYPE_SIZE_UNIT trees looking for VAR_DECLs. Those VAR_DECLs will be
! marked as having a hidden use. */
static tree
find_hidden_use_vars_r (tp, walk_subtrees, data)
--- 2571,2580 ----
return 0;
}
! /* Callback for walk_tree used by find_hidden_use_vars to analyze each
! variable in a lexical block. If the variable's size has a variable
! size, then mark all objects needed to compute the variable's size
! as having hidden uses. */
static tree
find_hidden_use_vars_r (tp, walk_subtrees, data)
*************** find_hidden_use_vars_r (tp, walk_subtree
*** 2584,2595 ****
{
int *inside_vla = (int *) data;
! if (TREE_CODE (*tp) == ARRAY_TYPE)
{
*inside_vla = 1;
! walk_tree (&TYPE_SIZE (*tp), find_hidden_use_vars_r, inside_vla, NULL);
! walk_tree (&TYPE_SIZE_UNIT (*tp), find_hidden_use_vars_r,
inside_vla, NULL);
}
else if (*inside_vla && SSA_DECL_P (*tp))
set_has_hidden_use (*tp);
--- 2584,2607 ----
{
int *inside_vla = (int *) data;
! /* We need to look for hidden uses due to VLAs in variable
! definitions. We originally used to look for these hidden
! uses in the variable's type, but that's unreliable if the
! type's size contains a SAVE_EXPR for a different function
! context than the variable is used within. */
! if (SSA_DECL_P (*tp)
! && ((DECL_SIZE (*tp)
! && ! really_constant_p (DECL_SIZE (*tp)))
! || (DECL_SIZE_UNIT (*tp)
! && ! really_constant_p (DECL_SIZE_UNIT (*tp)))))
{
+ int save = *inside_vla;
+
*inside_vla = 1;
! walk_tree (&DECL_SIZE (*tp), find_hidden_use_vars_r, inside_vla, NULL);
! walk_tree (&DECL_SIZE_UNIT (*tp), find_hidden_use_vars_r,
inside_vla, NULL);
+ *inside_vla = save;
}
else if (*inside_vla && SSA_DECL_P (*tp))
set_has_hidden_use (*tp);