This is the mail archive of the gcc-patches@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]
Other format: [Raw text]

Xtensa: commited fix for broken copy from register a7


This patch fixes a problem related to the special treatment that the Xtensa port uses when copying an incoming argument value from the a7 register. This special case should only be performed once per function. I've added a flag to mark when it has been done so that subsequent copies from a7 don't do anything special. I've tested this by running the testsuite with the xtensa-elf target. Committed on the mainline. Since this problem showed up as a regression on the 3.2 branch, I will also commit the patch on the branch whenever it reopens following the 3.2.1 release.
2002-11-21  Bob Wilson  <bob.wilson@acm.org>

        * config/xtensa/xtensa-protos.h (xtensa_copy_incoming_a7): Declare.
        * config/xtensa/xtensa.c (struct machine_function): Add
        incoming_a7_copied flag.
        (xtensa_copy_incoming_a7): Define.
        (xtensa_emit_move_sequence): Use xtensa_copy_incoming_a7.
        * config/xtensa/xtensa.md (movdi, movsf, movdf): Ditto.

Index: xtensa-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa-protos.h,v
retrieving revision 1.5
diff -c -3 -r1.5 xtensa-protos.h
*** xtensa-protos.h	30 Sep 2002 20:25:44 -0000	1.5
--- xtensa-protos.h	22 Nov 2002 00:22:07 -0000
***************
*** 70,75 ****
--- 70,76 ----
  extern int xtensa_expand_scc PARAMS ((rtx *));
  extern int xtensa_expand_block_move PARAMS ((rtx *));
  extern int xtensa_emit_move_sequence PARAMS ((rtx *, enum machine_mode));
+ extern bool xtensa_copy_incoming_a7 PARAMS ((rtx *, enum machine_mode));
  extern void xtensa_emit_block_move PARAMS ((rtx *, rtx *, int));
  extern void xtensa_expand_nonlocal_goto PARAMS ((rtx *));
  extern void xtensa_emit_loop_end PARAMS ((rtx, rtx *));
Index: xtensa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.c,v
retrieving revision 1.20
diff -c -3 -r1.20 xtensa.c
*** xtensa.c	30 Sep 2002 20:25:44 -0000	1.20
--- xtensa.c	22 Nov 2002 00:22:07 -0000
***************
*** 90,95 ****
--- 90,96 ----
  struct machine_function GTY(())
  {
    int accesses_prev_frame;
+   bool incoming_a7_copied;
  };
  
  /* Vector, indexed by hard register number, which contains 1 for a
***************
*** 1275,1319 ****
        if (!xtensa_valid_move (mode, operands))
  	operands[1] = force_reg (mode, operands[1]);
  
!       /* Check if this move is copying an incoming argument in a7.  If
! 	 so, emit the move, followed by the special "set_frame_ptr"
! 	 unspec_volatile insn, at the very beginning of the function.
! 	 This is necessary because the register allocator will ignore
! 	 conflicts with a7 and may assign some other pseudo to a7.  If
! 	 that pseudo was assigned prior to this move, it would clobber
! 	 the incoming argument in a7.  By copying the argument out of
! 	 a7 as the very first thing, and then immediately following
! 	 that with an unspec_volatile to keep the scheduler away, we
! 	 should avoid any problems.  */
! 
!       if (a7_overlap_mentioned_p (operands[1]))
! 	{
! 	  rtx mov;
! 	  switch (mode)
! 	    {
! 	    case SImode:
! 	      mov = gen_movsi_internal (operands[0], operands[1]);
! 	      break;
! 	    case HImode:
! 	      mov = gen_movhi_internal (operands[0], operands[1]);
! 	      break;
! 	    case QImode:
! 	      mov = gen_movqi_internal (operands[0], operands[1]);
! 	      break;
! 	    default:
! 	      abort ();
! 	    }
! 
! 	  /* Insert the instructions before any other argument copies.
! 	     (The set_frame_ptr insn comes _after_ the move, so push it
! 	     out first.)  */
! 	  push_topmost_sequence ();
! 	  emit_insn_after (gen_set_frame_ptr (), get_insns ());
! 	  emit_insn_after (mov, get_insns ());
! 	  pop_topmost_sequence ();
! 
! 	  return 1;
! 	}
      }
  
    /* During reload we don't want to emit (subreg:X (mem:Y)) since that
--- 1276,1283 ----
        if (!xtensa_valid_move (mode, operands))
  	operands[1] = force_reg (mode, operands[1]);
  
!       if (xtensa_copy_incoming_a7 (operands, mode))
! 	return 1;
      }
  
    /* During reload we don't want to emit (subreg:X (mem:Y)) since that
***************
*** 1342,1347 ****
--- 1306,1379 ----
        x = alter_subreg (&temp);
      }
    return x;
+ }
+ 
+ 
+ /* Check if this move is copying an incoming argument in a7.  If so,
+    emit the move, followed by the special "set_frame_ptr"
+    unspec_volatile insn, at the very beginning of the function.  This
+    is necessary because the register allocator will ignore conflicts
+    with a7 and may assign some other pseudo to a7.  If that pseudo was
+    assigned prior to this move, it would clobber the incoming argument
+    in a7.  By copying the argument out of a7 as the very first thing,
+    and then immediately following that with an unspec_volatile to keep
+    the scheduler away, we should avoid any problems.  */
+ 
+ bool
+ xtensa_copy_incoming_a7 (operands, mode)
+      rtx *operands;
+      enum machine_mode mode;
+ {
+   if (a7_overlap_mentioned_p (operands[1])
+       && !cfun->machine->incoming_a7_copied)
+     {
+       rtx mov;
+       switch (mode)
+ 	{
+ 	case DFmode:
+ 	  mov = gen_movdf_internal (operands[0], operands[1]);
+ 	  break;
+ 	case SFmode:
+ 	  mov = gen_movsf_internal (operands[0], operands[1]);
+ 	  break;
+ 	case DImode:
+ 	  mov = gen_movdi_internal (operands[0], operands[1]);
+ 	  break;
+ 	case SImode:
+ 	  mov = gen_movsi_internal (operands[0], operands[1]);
+ 	  break;
+ 	case HImode:
+ 	  mov = gen_movhi_internal (operands[0], operands[1]);
+ 	  break;
+ 	case QImode:
+ 	  mov = gen_movqi_internal (operands[0], operands[1]);
+ 	  break;
+ 	default:
+ 	  abort ();
+ 	}
+ 
+       /* Insert the instructions before any other argument copies.
+ 	 (The set_frame_ptr insn comes _after_ the move, so push it
+ 	 out first.)  */
+       push_topmost_sequence ();
+       emit_insn_after (gen_set_frame_ptr (), get_insns ());
+       emit_insn_after (mov, get_insns ());
+       pop_topmost_sequence ();
+ 
+       /* Ideally the incoming argument in a7 would only be copied
+ 	 once, since propagating a7 into the body of a function
+ 	 will almost certainly lead to errors.  However, there is
+ 	 at least one harmless case (in GCSE) where the original
+ 	 copy from a7 is changed to copy into a new pseudo.  Thus,
+ 	 we use a flag to only do this special treatment for the
+ 	 first copy of a7.  */
+ 
+       cfun->machine->incoming_a7_copied = true;
+ 
+       return 1;
+     }
+ 
+   return 0;
  }
  
  
Index: xtensa.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.md,v
retrieving revision 1.6
diff -c -3 -r1.6 xtensa.md
*** xtensa.md	27 Jun 2002 23:17:46 -0000	1.6
--- xtensa.md	22 Nov 2002 00:22:07 -0000
***************
*** 929,940 ****
  	  && !register_operand (operands[1], DImode))
  	operands[1] = force_reg (DImode, operands[1]);
  
!       if (a7_overlap_mentioned_p (operands[1]))
! 	{
! 	  emit_insn (gen_movdi_internal (operands[0], operands[1]));
! 	  emit_insn (gen_set_frame_ptr ());
! 	  DONE;
! 	}
      }
  }")
  
--- 929,936 ----
  	  && !register_operand (operands[1], DImode))
  	operands[1] = force_reg (DImode, operands[1]);
  
!       if (xtensa_copy_incoming_a7 (operands, DImode))
! 	DONE;
      }
  }")
  
***************
*** 1107,1118 ****
  	      && constantpool_mem_p (operands[1]))))
  	operands[1] = force_reg (SFmode, operands[1]);
  
!       if (a7_overlap_mentioned_p (operands[1]))
! 	{
! 	  emit_insn (gen_movsf_internal (operands[0], operands[1]));
! 	  emit_insn (gen_set_frame_ptr ());
! 	  DONE;
! 	}
      }
  }")
  
--- 1103,1110 ----
  	      && constantpool_mem_p (operands[1]))))
  	operands[1] = force_reg (SFmode, operands[1]);
  
!       if (xtensa_copy_incoming_a7 (operands, SFmode))
! 	DONE;
      }
  }")
  
***************
*** 1193,1204 ****
  	  && !register_operand (operands[1], DFmode))
  	operands[1] = force_reg (DFmode, operands[1]);
  
!       if (a7_overlap_mentioned_p (operands[1]))
! 	{
! 	  emit_insn (gen_movdf_internal (operands[0], operands[1]));
! 	  emit_insn (gen_set_frame_ptr ());
! 	  DONE;
! 	}
      }
  }")
  
--- 1185,1192 ----
  	  && !register_operand (operands[1], DFmode))
  	operands[1] = force_reg (DFmode, operands[1]);
  
!       if (xtensa_copy_incoming_a7 (operands, DFmode))
! 	DONE;
      }
  }")
  

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