This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Another NaT bit propagation bug.


>> On Wed, Nov 07, 2001 at 06:13:47AM -0800, amacleod@cygnus.com wrote:
>> > The simplest way to handle this is to look for any registers which
>> > are live on entry to the function, check to see if their first use is
>> > in a zero_extract or subreg expression, and if so, set them to 0 immediately
>> > following the prologue. Since this is specific to ia64, I've put the
>> > code into ia64_reorg.
>> 
>> I don't think this is really ia64 specific.  Well, the NaT death
>> is, but not the general problem.  Consider

...

>> It would be nice to handle this in a generic fashion before 
>> combine, so that combine can simplify the masking.

OK, here's another patch (does this look familiar by the way? :-) which does
that. I couldn't find a decent/logical place to put the 2 routines
that are currently in toplev.c... suggestions?   We can use the flag to
selectivly turn on the optimization just for the targets we care about.
And speaking of the flag... I'm open to suggestions for renaming it too :-)

This bootstrapped and ran fine a couple of weeks ago, Im rerunning it again now
to verify everything is still ok.

Andrew




	* flags.h (flag_no_garbage_regs): New flag.
	* toplev.c (flag_no_garbage_regs): Initialize.
	(f_options): Add no-garbage-regs flag.
	(find_regno_partial): New.
	(initialize_uninitialized_subregs): New.
	(rest_of_compilation): Call initialize_uninitialized_subregs.
	* config/ia64/ia64.c (ia64_override_options): Set flag_no_garbage_regs.
	* doc/invoke.texi (no-garbage-regs): Add documention.


Index: flags.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flags.h,v
retrieving revision 1.57.4.3
diff -c -p -r1.57.4.3 flags.h
*** flags.h	2001/05/12 20:55:52	1.57.4.3
--- flags.h	2001/10/12 14:55:09
*************** extern int flag_gnu_linker;
*** 498,503 ****
--- 498,509 ----
  /* Tag all structures with __attribute__(packed) */
  extern int flag_pack_struct;
  
+ /* Indicates that any registers *initially* set via some form of a mask 
+    instruction should be cleared prior to masking.  This is used to prevent
+    propagation of incorrect sticky bits from unknown values.  Typically
+    this would occur with bitfield operations.  */
+ extern int flag_no_garbage_regs;
+ 
  /* This flag is only tested if alias checking is enabled.
     0 if pointer arguments may alias each other.  True in C.
     1 if pointer arguments may not alias each other but may alias
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.420.2.31
diff -c -p -r1.420.2.31 toplev.c
*** toplev.c	2001/06/26 19:27:49	1.420.2.31
--- toplev.c	2001/10/12 14:55:13
*************** int flag_dce = 0;
*** 811,816 ****
--- 811,819 ----
  /* Tag all structures with __attribute__(packed).  */
  int flag_pack_struct = 0;
  
+ /* Registers which are initially set with a mask should be cleared first.  */
+ int flag_no_garbage_regs = 0;
+ 
  /* Emit code to check for stack overflow; also may cause large objects
     to be allocated dynamically.  */
  int flag_stack_check;
*************** lang_independent_options f_options[] =
*** 1097,1102 ****
--- 1100,1107 ----
     N_("Do the full regmove optimization pass") },
    {"pack-struct", &flag_pack_struct, 1,
     N_("Pack structure members together without holes") },
+   {"no-garbage-regs", &flag_no_garbage_regs, 1,
+    N_("Clear any sticky bits from bitfield registers before first use") },
    {"stack-check", &flag_stack_check, 1,
     N_("Insert stack checking code into the program") },
    {"argument-alias", &flag_argument_noalias, 0,
*************** note_outlining_of_inline_function (fndec
*** 2723,2728 ****
--- 2728,2827 ----
  #endif
  }
  
+ 
+ int initialize_uninitialized_subregs	PARAMS ((void));
+ int find_regno_partial			PARAMS ((rtx *, void *));
+ 
+ static rtx find_regno_retval;   /* Used to return a value from func.  */
+ 
+ /* Find the rtx for the reg numbers specified in 'data' if it is
+    part of an expression which only uses part of the register.  Return
+    it in func_retval.  */
+ int find_regno_partial (ptr, data)
+      rtx *ptr;
+      void *data;
+ {
+   unsigned reg = *((unsigned *)data);
+   if (*ptr == NULL_RTX)
+     return 0;
+ 
+   switch (GET_CODE (*ptr)) 
+     {
+       case ZERO_EXTRACT:
+       case SIGN_EXTRACT:
+       case STRICT_LOW_PART:
+         if (GET_CODE (XEXP (*ptr, 0)) == REG && REGNO (XEXP (*ptr, 0)) == reg)
+ 	  {
+ 	    find_regno_retval = *ptr;
+ 	    return 1;
+ 	  }
+ 	break;
+ 
+       case SUBREG:
+         if (GET_CODE (SUBREG_REG (*ptr)) == REG 
+ 	    && REGNO (SUBREG_REG (*ptr)) == reg)
+ 	  {
+ 	    find_regno_retval = *ptr;
+ 	    return 1;
+ 	  }
+ 	break;
+     }
+ 
+   return 0;
+ }
+ 
+ /* Process all immediate successors of the entry block looking for pseudo
+    registers which are live on entry. Find all of those whose first 
+    instance is a partial register reference of some kind, and initialize 
+    them to 0 after the entry block.  This will prevent bit sets within
+    registers whose value is unknown, and may contain some kind of sticky 
+    bits we don't want.  */
+ 
+ int
+ initialize_uninitialized_subregs () 
+ {
+   rtx insn, x;
+   edge e;
+   int reg, did_something = 0;
+   for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
+     {
+       basic_block bb = e->dest;
+       regset map = bb->global_live_at_start;
+       EXECUTE_IF_SET_IN_REG_SET (map,
+ 				 FIRST_PSEUDO_REGISTER, reg,
+ 	{
+ 	  int uid = REGNO_FIRST_UID (reg);
+ 	  rtx i;
+ 
+ 	  /* Find an insn which mentions the register we are looking for.
+ 	     Its preferable to have an instance of the register's rtl since
+ 	     there may be various flags set which we need to duplicate.  
+ 	     If we can't find it, its probably an automatic whose initial
+ 	     value doesnt matter, or hopefully something we dont care about. */
+ 	  for (i = get_insns (); i && INSN_UID (i) != uid; i = NEXT_INSN (i))
+ 	    ;
+ 	  if (i != NULL_RTX)
+ 	    {
+ 	      /* Found the insn, now get the REG rtx, if we can.  */
+ 	      find_regno_retval = NULL_RTX;
+ 	      for_each_rtx (&i, find_regno_partial, &reg);
+ 	      if (find_regno_retval != NULL_RTX)
+ 		{
+ 		  x = find_regno_retval;
+ 		  insn = gen_move_insn (x, CONST0_RTX (GET_MODE (x)));
+ 		  insert_insn_on_edge (insn, e);
+ 		  did_something = 1;
+ 		}
+ 	    }
+ 	});
+     }
+ 
+   if (did_something)
+     commit_edge_insertions ();
+   return did_something;
+ }
+ 
+ 
  /* This is called from finish_function (within yyparse)
     after each top-level definition is parsed.
     It is supposed to compile that function or variable
*************** rest_of_compilation (decl)
*** 3308,3313 ****
--- 3407,3422 ----
        uninitialized_vars_warning (DECL_INITIAL (decl));
        if (extra_warnings)
  	setjmp_args_warning ();
+     }
+ 
+   if (optimize && flag_no_garbage_regs)
+     {
+       if (initialize_uninitialized_subregs ())
+ 	{
+ 	  /* Insns were inserted, so things might look a bit different.  */
+ 	  insns = get_insns();
+ 	  life_analysis (insns, rtl_dump_file, PROP_REG_INFO);
+ 	}
      }
  
    close_dump_file (DFI_life, print_rtl_with_bb, insns);
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.c,v
retrieving revision 1.72.2.17
diff -c -p -r1.72.2.17 ia64.c
*** ia64.c	2001/09/19 19:17:21	1.72.2.17
--- ia64.c	2001/10/12 14:55:17
*************** ia64_override_options ()
*** 3754,3759 ****
--- 3754,3764 ----
    ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload;
    flag_schedule_insns_after_reload = 0;
  
+   /* Make sure regs initially set via a partial register operation are
+      cleared first so that NAT bits aren't mistakenly propagated from
+      an unkown register value.  */
+   flag_no_garbage_regs = 1;
+ 
    ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE;
  
    init_machine_status = ia64_init_machine_status;
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/doc/invoke.texi,v
retrieving revision 1.3.2.25
diff -c -p -r1.3.2.25 invoke.texi
*** invoke.texi	2001/09/05 08:31:59	1.3.2.25
--- invoke.texi	2001/10/12 14:55:25
*************** in the following sections.
*** 271,277 ****
  -fschedule-insns  -fschedule-insns2 @gol
  -fsingle-precision-constant  -fssa @gol
  -fstrength-reduce  -fstrict-aliasing  -fthread-jumps  -ftrapv @gol
! -funroll-all-loops  -funroll-loops  @gol
  --param @var{name}=@var{value}
  -O  -O0  -O1  -O2  -O3  -Os}
  
--- 271,277 ----
  -fschedule-insns  -fschedule-insns2 @gol
  -fsingle-precision-constant  -fssa @gol
  -fstrength-reduce  -fstrict-aliasing  -fthread-jumps  -ftrapv @gol
! -funroll-all-loops  -funroll-loops  -fno-garbage-regs@gol
  --param @var{name}=@var{value}
  -O  -O0  -O1  -O2  -O3  -Os}
  
*************** performed.
*** 3393,3398 ****
--- 3393,3405 ----
  @item -frerun-loop-opt
  @opindex frerun-loop-opt
  Run the loop optimizer twice.
+ 
+ @item -fno-garbage-regs
+ @opindex no-garbage-regs
+ Initialize any registers to 0 when the first set of that register is via a 
+ bitwise operation.  This prevents the propagation of any unwanted sticky 
+ bits which might occur through setting bits in a registers whose value 
+ is not known.
  
  @item -fgcse
  @opindex fgcse



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]