On Thu, 12 Nov 2020, Jan Hubicka wrote:
> Hi,
> with ipa-icf we often run into problem that operand_equal_p does not
> match ADDR_EXPR that take address of fields from two different instances
> of same class (at ideantical offsets). Similar problem can also happen
> for record types with LTO if they did not get tree merged.
> This patch makes fold-const to compare offsets rather then pinter
> equality of FIELD_DECLs. This is done in OEP_ADDRESS_OF mode only sinc
> it is not TBAA safe and the TBAA side should be correctly solved by my
> ICF patch.
>
> Bootstrapped/regtested x86_64-linux, OK?
>
> Honza
>
> * fold-const.c (operand_compare::operand_equal_p): When comparing
> addresses
> look info field offsets for COMPONENT_REFs.
> (operand_compare::hash_operand): Likewise.
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index c47557daeba..a4e8cccb1b7 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -3312,9 +3312,41 @@ operand_compare::operand_equal_p (const_tree arg0,
> const_tree arg1,
> case COMPONENT_REF:
> /* Handle operand 2 the same as for ARRAY_REF. Operand 0
> may be NULL when we're called to compare MEM_EXPRs. */
> - if (!OP_SAME_WITH_NULL (0)
> - || !OP_SAME (1))
> + if (!OP_SAME_WITH_NULL (0))
> return false;
> + /* Most of time we only need to compare FIELD_DECLs for equality.
> + However when determining address look into actual offsets.
> + These may match for unions and unshared record types. */
> + if (!OP_SAME (1))
> + {
> + if (flags & OEP_ADDRESS_OF)
> + {
actually if OP2 is not NULL for both you can just compare that (and that's
more correct then).
> + tree field0 = TREE_OPERAND (arg0, 1);
> + tree field1 = TREE_OPERAND (arg1, 1);
> + tree type0 = DECL_CONTEXT (field0);
> + tree type1 = DECL_CONTEXT (field1);
> +
> + if (TREE_CODE (type0) == RECORD_TYPE
> + && DECL_BIT_FIELD_REPRESENTATIVE (field0))
> + field0 = DECL_BIT_FIELD_REPRESENTATIVE (field0);
> + if (TREE_CODE (type1) == RECORD_TYPE
> + && DECL_BIT_FIELD_REPRESENTATIVE (field1))
> + field1 = DECL_BIT_FIELD_REPRESENTATIVE (field1);
Why does the representative matter? For a 32bit bitfield if you'd
have two addresses at 8bit boundary but different you'd make them
equal this way. Soo ...
> + /* Assume that different FIELD_DECLs never overlap within a
> + RECORD_TYPE. */
> + if (type0 == type1 && TREE_CODE (type0) == RECORD_TYPE)
> + return false;
this isn't really about "overlap", OEP_ADDRESS_OF is just about
the address (not it's extent).
> + if (!operand_equal_p (DECL_FIELD_OFFSET (field0),
> + DECL_FIELD_OFFSET (field1),
> + flags & ~OEP_ADDRESS_OF)
> + || !operand_equal_p (DECL_FIELD_BIT_OFFSET (field0),
> + DECL_FIELD_BIT_OFFSET (field1),
> + flags & ~OEP_ADDRESS_OF))
> + return false;
So this should suffice (on the original fields).
> + }
> + else
> + return false;
> + }
> flags &= ~OEP_ADDRESS_OF;
> return OP_SAME_WITH_NULL (2);
>
> @@ -3787,9 +3819,28 @@ operand_compare::hash_operand (const_tree t,
> inchash::hash &hstate,
> sflags = flags;
> break;
>
> + case COMPONENT_REF:
> + if (flags & OEP_ADDRESS_OF)
> + {
> + tree field = TREE_OPERAND (t, 1);
> + tree type = DECL_CONTEXT (field);
> +
> + if (TREE_CODE (type) == RECORD_TYPE
> + && DECL_BIT_FIELD_REPRESENTATIVE (field))
> + field = DECL_BIT_FIELD_REPRESENTATIVE (field);
see above.
> + hash_operand (TREE_OPERAND (t, 0), hstate, flags);
> + hash_operand (DECL_FIELD_OFFSET (field),
> + hstate, flags & ~OEP_ADDRESS_OF);
> + hash_operand (DECL_FIELD_BIT_OFFSET (field),
> + hstate, flags & ~OEP_ADDRESS_OF);
> + hash_operand (TREE_OPERAND (t, 2), hstate,
> + flags & ~OEP_ADDRESS_OF);
otherwise this looks ok.
> + return;
> + }
> + break;
> case ARRAY_REF:
> case ARRAY_RANGE_REF:
> - case COMPONENT_REF:
> case BIT_FIELD_REF:
> sflags &= ~OEP_ADDRESS_OF;
> break;
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imend