How to update reg_dead notes

2015-02-24 Thread Georg-Johann Lay
Hi, in order to fix PR64331 I tried to implement new target-specific passes 
whose sole purpose is to recompute REG_DEAD notes.


The avr BE relies on correct dead notes which are used in 
avr.c:reg_unused_after which uses dead_or_set_p.  avr BE needs correct dead 
notes in ADJUST_INSN_LENGTH, get_attr_length, get_attr_min_length, etc.


After trying for more than one day I am really frustrated; each approach ended 
up in seg_faults somewhere in df.


Following the source comments in df-core.c, recomputing dead notes should be as 
easy as



  df_note_add_problem ();
  df_analyze ();

in the execute() method of the new pass.


As this (and many many other tries using df_scan_alloc, df_scan_blocks 
df_finish_pass, df_insn_rescan_all, etc.) always crashes the compiler, I must 
do something completely wrong...


Could you give me some advice on correct usage of df or even more preferred 
point me to a comprehensible documentation of df which is more complete than in 
df-core.c?


Internals don't treat df, and the source comments are not really helpful, e.g. 
the complete documentation of df_analyze is /* Analyze dataflow info.  */.  Not 
a single word about prerequisites (except that it must run after df_init and 
before df_finish and needs correct cfg).


One example of a crash is that df->insns[uid] is being accessed and 
dereferenced where uid is a valid uid but df->insns[uid] is NULL.


df-core.c mentions "given instances of df".  How do I get one? The only 
instance I can find is the global struct df_f *df.  Does this mean one has to 
mess around with that global variable?





Re: How to update reg_dead notes

2015-02-24 Thread Kenneth Zadeck
It is generally as easy as just adding the problem and calling 
df_analyze.  You tend to get into trouble if the rtl is not good, i.e. 
there is improper sharing or other violations of the canonical rtl 
rules.  DF does not like improperly shared rtl and it has not been 
uncommon for port specific passes to play loose with these rules.   I 
would suggest that first you try a build where you turn on all of the 
rtl checking and see if that comes out clean.


Kenny

On 02/24/2015 06:41 AM, Georg-Johann Lay wrote:
Hi, in order to fix PR64331 I tried to implement new target-specific 
passes whose sole purpose is to recompute REG_DEAD notes.


The avr BE relies on correct dead notes which are used in 
avr.c:reg_unused_after which uses dead_or_set_p.  avr BE needs correct 
dead notes in ADJUST_INSN_LENGTH, get_attr_length, 
get_attr_min_length, etc.


After trying for more than one day I am really frustrated; each 
approach ended up in seg_faults somewhere in df.


Following the source comments in df-core.c, recomputing dead notes 
should be as easy as



  df_note_add_problem ();
  df_analyze ();

in the execute() method of the new pass.


As this (and many many other tries using df_scan_alloc, df_scan_blocks 
df_finish_pass, df_insn_rescan_all, etc.) always crashes the compiler, 
I must do something completely wrong...


Could you give me some advice on correct usage of df or even more 
preferred point me to a comprehensible documentation of df which is 
more complete than in df-core.c?


Internals don't treat df, and the source comments are not really 
helpful, e.g. the complete documentation of df_analyze is /* Analyze 
dataflow info.  */.  Not a single word about prerequisites (except 
that it must run after df_init and before df_finish and needs correct 
cfg).


One example of a crash is that df->insns[uid] is being accessed and 
dereferenced where uid is a valid uid but df->insns[uid] is NULL.


df-core.c mentions "given instances of df".  How do I get one? The 
only instance I can find is the global struct df_f *df.  Does this 
mean one has to mess around with that global variable?







Re: How to update reg_dead notes

2015-02-24 Thread Oleg Endo
On Tue, 2015-02-24 at 16:59 +0100, Georg-Johann Lay wrote:

It doesn't really answer your question, but just as a side note, the
following ...

> +  struct register_pass_info insert_before_bbro =
> +{
> +  notes_bbro_pass,  /* pass */
> +  "bbro",   /* reference_pass_name */
> +  1,/* ref_pass_instance_number */
> +  PASS_POS_INSERT_BEFORE/* position */
> +};
> +
> +  struct register_pass_info insert_before_compgotos =
> +{
> +  notes_compgotos_pass, /* pass */
> +  "compgotos",  /* reference_pass_name */
> +  1,/* ref_pass_instance_number */
> +  PASS_POS_INSERT_BEFORE/* position */
> +};
> +
> +  struct register_pass_info insert_before_shorten =
> +{
> +  notes_shorten_pass,   /* pass */
> +  "shorten",/* reference_pass_name */
> +  1,/* ref_pass_instance_number */
> +  PASS_POS_INSERT_BEFORE/* position */
> +};
> +
> +  struct register_pass_info insert_before_final =
> +{
> +  notes_final_pass, /* pass */
> +  "final",  /* reference_pass_name */
> +  1,/* ref_pass_instance_number */
> +  PASS_POS_INSERT_BEFORE/* position */
> +};
> +
> +  register_pass (&insert_before_bbro);
> +  register_pass (&insert_before_compgotos);
> +  register_pass (&insert_before_shorten);
> +  register_pass (&insert_before_final);

... can be done in 4 lines of code, without all the struct stuff to pass
function arguments.  See also "register_pass" calls in config/sh/sh.c.

Cheers,
Oleg



Re: How to update reg_dead notes

2015-02-24 Thread Georg-Johann Lay

Am 02/24/2015 um 02:11 PM schrieb Kenneth Zadeck:

On 02/24/2015 06:41 AM, Georg-Johann Lay wrote:

Hi, in order to fix PR64331 I tried to implement new target-specific passes
whose sole purpose is to recompute REG_DEAD notes.

The avr BE relies on correct dead notes which are used in
avr.c:reg_unused_after which uses dead_or_set_p.  avr BE needs correct dead
notes in ADJUST_INSN_LENGTH, get_attr_length, get_attr_min_length, etc.

After trying for more than one day I am really frustrated; each approach
ended up in seg_faults somewhere in df.

Following the source comments in df-core.c, recomputing dead notes should be
as easy as


  df_note_add_problem ();
  df_analyze ();

in the execute() method of the new pass.


As this (and many many other tries using df_scan_alloc, df_scan_blocks
df_finish_pass, df_insn_rescan_all, etc.) always crashes the compiler, I must
do something completely wrong...

Could you give me some advice on correct usage of df or even more preferred
point me to a comprehensible documentation of df which is more complete than
in df-core.c?


Hi, thanks for answering.


It is generally as easy as just adding the problem and calling df_analyze.
You tend to get into trouble if the rtl is not good, i.e. there is improper 
sharing or other violations of the canonical rtl rules.  DF does not like 
improperly shared rtl and it has not been uncommon for port specific passes to 
play loose with these rules.


Currently there are no port-specific passes. The only port-specific passes are 
the new passes which I am trying to add in order to keep REG_DEAD notes up to date.



I would suggest that first you try a build where you turn on all of the rtl 
checking and see if that comes out clean.

Kenny


Okay, here we go.  I configured avr-gcc from recent 4.9-branch with 
--enable-checking=all on x86-linux-gnu:


$ ../../gcc.gnu.org/gcc-4_9-branch/configure --target=avr 
--prefix=/local/gnu/install/gcc-4.9 --disable-nls --with-dwarf2 
--enable-target-optspace=yes --with-gnu-ld --with-gnu-as 
--enable-languages=c,c++ --enable-checking=all


The passes are added by means of the attached patch and installed right before 
passes which might use avr.c:reg_unused_after, i.e. passes that query for 
(minimum) insn lengths: .bbro, .compgotos, .shorten and .final.


The compiler crashes when it builds libgcc.  The test case is attached as 
libgcc2-addvsi3.c and compiled as


$ path-to-xgcc/xgcc -B path-to-xgcc -S libgcc2-addvsi3.c


The crash message (same with optimization) is for the pass which has been added 
just before .shorten:



libgcc2-addvsi3.c: In function '__addvhi3':
libgcc2-addvsi3.c:1514:1: internal compiler error: in df_refs_verify, at 
df-scan.c:4323

 }
 ^
0x82dfe8a df_refs_verify
../../../gcc.gnu.org/gcc-4_9-branch/gcc/df-scan.c:4323
0x82e7b34 df_insn_refs_verify
../../../gcc.gnu.org/gcc-4_9-branch/gcc/df-scan.c:4414
0x82e9906 df_bb_verify
../../../gcc.gnu.org/gcc-4_9-branch/gcc/df-scan.c:4441
0x82e9d8e df_scan_verify()
../../../gcc.gnu.org/gcc-4_9-branch/gcc/df-scan.c:4573
0x82d3787 df_verify()
../../../gcc.gnu.org/gcc-4_9-branch/gcc/df-core.c:1862
0x82d3809 df_analyze_1
../../../gcc.gnu.org/gcc-4_9-branch/gcc/df-core.c:1250
0x896188b avr_pass_recompute_notes::execute()
../../../gcc.gnu.org/gcc-4_9-branch/gcc/config/avr/avr.c:317
Please submit a full bug report,


Johann

Index: config/avr/avr.c
===
--- config/avr/avr.c	(revision 220738)
+++ config/avr/avr.c	(working copy)
@@ -51,6 +51,8 @@
 #include "target-def.h"
 #include "params.h"
 #include "df.h"
+#include "context.h"
+#include "tree-pass.h"	/* for current_pass */
 
 /* Maximal allowed offset for an address in the LD command */
 #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -284,6 +286,48 @@ avr_to_int_mode (rtx x)
 : simplify_gen_subreg (int_mode_for_mode (mode), x, mode, 0);
 }
 
+
+static const pass_data avr_pass_data_recompute_notes =
+{
+  RTL_PASS, /* type */
+  "avr-notes1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_DF_SCAN, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+
+class avr_pass_recompute_notes : public rtl_opt_pass
+{
+public:
+  avr_pass_recompute_notes (gcc::context *ctxt)
+: rtl_opt_pass (avr_pass_data_recompute_notes, ctxt)
+  {}
+
+  /* opt_pass methods */
+  unsigned int execute ()
+  {
+df_note_add_problem ();
+df_analyze ();
+
+return 0;
+  }
+}; // avr_pass_recompute_notes
+
+
+static rtl_opt_pass*
+avr_make_pass_recompute_notes (gcc::context *ctxt, const char *name)
+{
+  rtl_opt_pass *pass = new avr_pass_recompute_notes (ctxt);
+  pass->name = name;
+  return pass;
+}
 
 /* Implement `TARGET_OPTION_OVERRIDE'.  */
 
@@ -346,6 +390,58 @@ avr_option_override (vo

Re: How to update reg_dead notes

2015-02-24 Thread Eric Botcazou
> Could you give me some advice on correct usage of df or even more preferred
> point me to a comprehensible documentation of df which is more complete than
> in df-core.c?

Take a look at the c6x and mep ports.

-- 
Eric Botcazou


Re: How to update reg_dead notes

2015-02-24 Thread Georg-Johann Lay

Am 02/24/2015 um 06:06 PM schrieb Eric Botcazou:

Could you give me some advice on correct usage of df or even more preferred
point me to a comprehensible documentation of df which is more complete than
in df-core.c?


Take a look at the c6x and mep ports.



Thanks for the hint.  I changed the execute method to:

unsigned int execute ()
  {
compute_bb_for_insn ();
//df_clear_flags (DF_LR_RUN_DCE);
df_note_add_problem ();
df_analyze ();
df_finish_pass (false);

return 0;
  }

bit it keeps aborting.  Actually I am just copy pasting code from some other 
passes / BEs, but these places also don't have explanation for why they must 
use, may use, must not use specific functions.


Compiling the mentioned test case from libgcc with -Os (so that less insns are 
left over) and patching df-scan.c:df_refs_verify to print the refs just before 
it does gcc_assert (0):


new_ref = { u-1(18){ }}
*old_rec = { u-1(18){ }u-1(19){ }u-1(24){ }u-1(25){ }}
libgcc2-addvsi3.c: In function '__addvhi3':
libgcc2-addvsi3.c:1514:1: internal compiler error: in df_refs_verify, at 
df-scan.c:4338


In df_insn_refs_verify which is in the call chain of df_refs_verify, insn reads:

(insn 21 19 22 5 (parallel [
(set (cc0)
(compare (reg/v:HI 18 r18 [orig:48 a ] [48])
(reg/v:HI 24 r24 [orig:46 w ] [46])))
(clobber (scratch:QI))
]) libgcc2-addvsi3.c:1511 408 {*cmphi}
 (expr_list:REG_DEAD (reg/v:HI 18 r18 [orig:48 a ] [48])
(nil)))

r18 and r24 are ordinary general-purpose hard registers.


The latest pass which runs before the crash is .split5, i.e. 
recog.c::pass_split_for_shorten_branches which executes split_all_insns_noflow 
which in turn reads:


/* Same as split_all_insns, but do not expect CFG to be available.
   Used by machine dependent reorg passes.  */

unsigned int
split_all_insns_noflow (void)
{ ...

Does this mean CFG is (or might be) messed up after this pass and this is the 
reason for why df crashes because df needs correct CFG?


Johann






Re: How to update reg_dead notes

2015-02-24 Thread Kenneth Zadeck
when i suggested that you do a build with all of the checking turned on, 
i wanted you to this without you new code in it.there is a good 
possibility that the problem is that your port is generating bad rtl.
Also, you should generate a debuggable compiler so that the line numbers 
have some relevance to reality.




On 02/24/2015 01:23 PM, Georg-Johann Lay wrote:

Am 02/24/2015 um 06:06 PM schrieb Eric Botcazou:
Could you give me some advice on correct usage of df or even more 
preferred
point me to a comprehensible documentation of df which is more 
complete than

in df-core.c?


Take a look at the c6x and mep ports.



Thanks for the hint.  I changed the execute method to:

unsigned int execute ()
  {
compute_bb_for_insn ();
//df_clear_flags (DF_LR_RUN_DCE);
df_note_add_problem ();
df_analyze ();
df_finish_pass (false);

return 0;
  }

bit it keeps aborting.  Actually I am just copy pasting code from some 
other passes / BEs, but these places also don't have explanation for 
why they must use, may use, must not use specific functions.


Compiling the mentioned test case from libgcc with -Os (so that less 
insns are left over) and patching df-scan.c:df_refs_verify to print 
the refs just before it does gcc_assert (0):


new_ref = { u-1(18){ }}
*old_rec = { u-1(18){ }u-1(19){ }u-1(24){ }u-1(25){ }}
libgcc2-addvsi3.c: In function '__addvhi3':
libgcc2-addvsi3.c:1514:1: internal compiler error: in df_refs_verify, 
at df-scan.c:4338


In df_insn_refs_verify which is in the call chain of df_refs_verify, 
insn reads:


(insn 21 19 22 5 (parallel [
(set (cc0)
(compare (reg/v:HI 18 r18 [orig:48 a ] [48])
(reg/v:HI 24 r24 [orig:46 w ] [46])))
(clobber (scratch:QI))
]) libgcc2-addvsi3.c:1511 408 {*cmphi}
 (expr_list:REG_DEAD (reg/v:HI 18 r18 [orig:48 a ] [48])
(nil)))

r18 and r24 are ordinary general-purpose hard registers.


The latest pass which runs before the crash is .split5, i.e. 
recog.c::pass_split_for_shorten_branches which executes 
split_all_insns_noflow which in turn reads:


/* Same as split_all_insns, but do not expect CFG to be available.
   Used by machine dependent reorg passes.  */

unsigned int
split_all_insns_noflow (void)
{ ...

Does this mean CFG is (or might be) messed up after this pass and this 
is the reason for why df crashes because df needs correct CFG?


Johann








Re: How to update reg_dead notes

2015-02-24 Thread Oleg Endo
On Tue, 2015-02-24 at 19:23 +0100, Georg-Johann Lay wrote:

> 
> The latest pass which runs before the crash is .split5, i.e. 
> recog.c::pass_split_for_shorten_branches which executes 
> split_all_insns_noflow 
> which in turn reads:
> 
> /* Same as split_all_insns, but do not expect CFG to be available.
> Used by machine dependent reorg passes.  */
> 
> unsigned int
> split_all_insns_noflow (void)
> { ...
> 
> Does this mean CFG is (or might be) messed up after this pass and this is the 
> reason for why df crashes because df needs correct CFG?

Yes, the CFG is only valid until some point.  E.g. on SH it stops being
valid after the machine reorg pass the latest (PR 59189).  Doing
anything CFG related after split5 might not be a good idea.

Cheers,
Oleg



Re: How to update reg_dead notes

2015-02-25 Thread Georg-Johann Lay

Am 02/24/2015 um 07:33 PM schrieb Kenneth Zadeck:

when i suggested that you do a build with all of the checking turned on, i
wanted you to this without you new code in it.there is a good possibility
that the problem is that your port is generating bad rtl.


Ah, ok.  This actually revealed an ice-checking; but that was not related to 
the df problems...


I think the problem was that I tried to run passes needing df after free_cfg.

My current solution works so far: It fixes the test case (correct code + insn 
lengths) and it did not ICE up to now.


Stuff is running a bit slow with all checks on so building and running tests 
will take a while...


FYI, you find my current patch attached.

Thanks for your help and time,

Johann



Index: config/avr/avr.c
===
--- config/avr/avr.c(revision 220963)
+++ config/avr/avr.c(working copy)
@@ -51,6 +51,8 @@
 #include "target-def.h"
 #include "params.h"
 #include "df.h"
+#include "context.h"
+#include "tree-pass.h"

 /* Maximal allowed offset for an address in the LD command */
 #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -285,6 +287,58 @@ avr_to_int_mode (rtx x)
 }


+static const pass_data avr_pass_data_recompute_notes =
+{
+  RTL_PASS, /* type */
+  "avr-xx", /* name (will be patched) */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_DF_SCAN, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  (TODO_df_finish | TODO_verify_rtl_sharing
+   | TODO_verify_flow ), /* todo_flags_finish */
+};
+
+
+class avr_pass_recompute_notes : public rtl_opt_pass
+{
+public:
+  avr_pass_recompute_notes (gcc::context *ctxt, const char *pass_name)
+: rtl_opt_pass (avr_pass_data_recompute_notes, ctxt)
+  {
+name = pass_name;
+  }
+
+  unsigned int execute ()
+  {
+df_note_add_problem ();
+df_analyze ();
+
+return 0;
+  }
+}; // avr_pass_recompute_notes
+
+
+static void
+avr_register_passes (void)
+{
+  /* This avr-specific pass (re)computes insn notes, in particular REG_DEAD
+ notes which are used by `avr.c::reg_unused_after' and branch offset
+ computations.  These notes must be correct, i.e. there must be no
+ dangling REG_DEAD notes; otherwise wrong code might result, cf. PR64331.
+
+ DF needs (correct) CFG, hence right before free_cfg is the last
+ opportunity to rectify notes.  */
+
+  register_pass (new avr_pass_recompute_notes (g, "avr-notes-free-cfg"),
+ PASS_POS_INSERT_BEFORE, "*free_cfg", 1);
+}
+
+
 /* Implement `TARGET_OPTION_OVERRIDE'.  */

 static void
@@ -346,6 +400,11 @@ avr_option_override (void)
   init_machine_status = avr_init_machine_status;

   avr_log_set_avr_log();
+
+  /* Register some avr-specific pass(es).  There is no canonical place for
+ pass registration.  This function is convenient.  */
+
+  avr_register_passes ();
 }

 /* Function to set up the backend function structure.  */



Re: How to update reg_dead notes

2015-02-25 Thread Kenneth Zadeck
it is a good policy to do a run with full checking every once in a 
while.   it is easy to have some garbage sneak in.df is particularly 
sensitive to bad rtl so that was my first suggestion.i had forgotten 
that df (as well as a lot of the infrastructure) does not work very late.

On 02/25/2015 01:54 PM, Georg-Johann Lay wrote:

Am 02/24/2015 um 07:33 PM schrieb Kenneth Zadeck:
when i suggested that you do a build with all of the checking turned 
on, i
wanted you to this without you new code in it.there is a good 
possibility

that the problem is that your port is generating bad rtl.


Ah, ok.  This actually revealed an ice-checking; but that was not 
related to the df problems...


I think the problem was that I tried to run passes needing df after 
free_cfg.


My current solution works so far: It fixes the test case (correct code 
+ insn lengths) and it did not ICE up to now.


Stuff is running a bit slow with all checks on so building and running 
tests will take a while...


FYI, you find my current patch attached.

Thanks for your help and time,

Johann



Index: config/avr/avr.c
===
--- config/avr/avr.c(revision 220963)
+++ config/avr/avr.c(working copy)
@@ -51,6 +51,8 @@
 #include "target-def.h"
 #include "params.h"
 #include "df.h"
+#include "context.h"
+#include "tree-pass.h"

 /* Maximal allowed offset for an address in the LD command */
 #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -285,6 +287,58 @@ avr_to_int_mode (rtx x)
 }


+static const pass_data avr_pass_data_recompute_notes =
+{
+  RTL_PASS, /* type */
+  "avr-xx", /* name (will be patched) */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_DF_SCAN, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  (TODO_df_finish | TODO_verify_rtl_sharing
+   | TODO_verify_flow ), /* todo_flags_finish */
+};
+
+
+class avr_pass_recompute_notes : public rtl_opt_pass
+{
+public:
+  avr_pass_recompute_notes (gcc::context *ctxt, const char *pass_name)
+: rtl_opt_pass (avr_pass_data_recompute_notes, ctxt)
+  {
+name = pass_name;
+  }
+
+  unsigned int execute ()
+  {
+df_note_add_problem ();
+df_analyze ();
+
+return 0;
+  }
+}; // avr_pass_recompute_notes
+
+
+static void
+avr_register_passes (void)
+{
+  /* This avr-specific pass (re)computes insn notes, in particular 
REG_DEAD

+ notes which are used by `avr.c::reg_unused_after' and branch offset
+ computations.  These notes must be correct, i.e. there must be no
+ dangling REG_DEAD notes; otherwise wrong code might result, cf. 
PR64331.

+
+ DF needs (correct) CFG, hence right before free_cfg is the last
+ opportunity to rectify notes.  */
+
+  register_pass (new avr_pass_recompute_notes (g, "avr-notes-free-cfg"),
+ PASS_POS_INSERT_BEFORE, "*free_cfg", 1);
+}
+
+
 /* Implement `TARGET_OPTION_OVERRIDE'.  */

 static void
@@ -346,6 +400,11 @@ avr_option_override (void)
   init_machine_status = avr_init_machine_status;

   avr_log_set_avr_log();
+
+  /* Register some avr-specific pass(es).  There is no canonical 
place for

+ pass registration.  This function is convenient.  */
+
+  avr_register_passes ();
 }

 /* Function to set up the backend function structure.  */