Hi, On Mon, Dec 01, 2014 at 12:00:14PM +0100, Richard Biener wrote: > On Fri, Nov 28, 2014 at 5:20 PM, Eric Botcazou <ebotca...@adacore.com> wrote: > > Hi, > > > > the attached Ada testcase triggers an assertion in the RTL expander for the > > address operator because the operator has been applied to a non-byte-aligned > > record field. The problematic ADDR_EXPR is built by > > ipa_modify_call_arguments > > which has a hole when get_addr_base_and_unit_offset returns NULL_TREE: the > > variable offset case is handled but not the non-byte-aligned case, which can > > rountinely happen in Ada, hence the proposed fix. > > > > Tested on x86_64-suse-linux, OK for the mainline? > > Umm. So you are doing a possibly aggregate copy here? Or how > are we sure we are dealing with a register op only? (the function > is always a twisted maze to me...) > > That said - I suppose this is called from IPA-SRA? In that case, > can't we please avoid doing the transform in the first place? >
I suppose that could be done by something like the following, which I have tested only very mildly so far, in particular I have not double checked that get_inner_reference is cfun-agnostic. Hope it helps, Martin 2014-12-03 Martin Jambor <mjam...@suse.cz> * tree-sra.c (ipa_sra_check_caller_data): New type. (has_caller_p): Removed. (ipa_sra_check_caller): New function. (ipa_sra_preliminary_function_checks): Use it. diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index f213c80..900f3c3 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -4977,13 +4977,54 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) return cfg_changed; } -/* If NODE has a caller, return true. */ +/* Means of communication between ipa_sra_check_caller and + ipa_sra_preliminary_function_checks. */ + +struct ipa_sra_check_caller_data +{ + bool has_callers; + bool bad_arg_alignment; +}; + +/* If NODE has a caller, mark that fact in DATA which is pointer to + ipa_sra_check_caller_data. Also check all aggregate arguments in all known + calls if they are unit aligned and if not, set the appropriate flag in DATA + too. */ static bool -has_caller_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +ipa_sra_check_caller (struct cgraph_node *node, void *data) { - if (node->callers) - return true; + if (!node->callers) + return false; + + struct ipa_sra_check_caller_data *iscc; + iscc = (struct ipa_sra_check_caller_data *) data; + iscc->has_callers = true; + + for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) + { + gimple call_stmt = cs->call_stmt; + unsigned count = gimple_call_num_args (call_stmt); + for (unsigned i = 0; i < count; i++) + { + tree arg = gimple_call_arg (call_stmt, i); + if (is_gimple_reg (arg)) + continue; + + tree offset; + HOST_WIDE_INT bitsize, bitpos; + machine_mode mode; + int unsignedp, volatilep = 0; + get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode, + &unsignedp, &volatilep, false); + if (bitpos % BITS_PER_UNIT) + { + iscc->bad_arg_alignment = true; + return true; + } + } + } + return false; } @@ -5038,14 +5079,6 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } - if (!node->call_for_symbol_thunks_and_aliases (has_caller_p, NULL, true)) - { - if (dump_file) - fprintf (dump_file, - "Function has no callers in this compilation unit.\n"); - return false; - } - if (cfun->stdarg) { if (dump_file) @@ -5064,6 +5097,25 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } + struct ipa_sra_check_caller_data iscc; + memset (&iscc, 0, sizeof(iscc)); + node->call_for_symbol_thunks_and_aliases (ipa_sra_check_caller, &iscc, true); + if (!iscc.has_callers) + { + if (dump_file) + fprintf (dump_file, + "Function has no callers in this compilation unit.\n"); + return false; + } + + if (iscc.bad_arg_alignment) + { + if (dump_file) + fprintf (dump_file, + "A function call has an argument with non-unit alignemnt.\n"); + return false; + } + return true; }