Re: [Patch, ARM][2/8] Epilogue in RTL: new patterns for int regs

2012-06-15 Thread Richard Earnshaw
On 31/05/12 14:53, Greta Yorsh wrote:
 This patch adds new define_insn patterns for epilogue with integer
 registers.
 
 The patterns can handle pop multiple with writeback and return (loading into
 PC directly).
 To handle return, the patterns use a new special predicate
 pop_multiple_return, that uses ldm_stm_operation_p function from a previous
 patch. To output assembly, the patterns use a new function
 arm_output_multireg_pop.
 
 This patch also adds a new function arm_emit_multi_reg_pop
 that emits RTL that matches the new pop patterns for integer registers.
 This is a helper function for epilogue expansion. It is used by a later
 patch.
 
 ChangeLog:
 
 gcc
 
 2012-05-31  Ian Bolton  ian.bol...@arm.com
 Sameera Deshpande  sameera.deshpa...@arm.com
 Greta Yorsh  greta.yo...@arm.com
 
 * config/arm/arm.md (load_multiple_with_writeback) New define_insn.
 (load_multiple, pop_multiple_with_writeback_and_return) Likewise.
 (pop_multiple_with_return, ldr_with_return) Likewise.
 * config/arm/predicates.md (pop_multiple_return) New special
 predicate.
 * config/arm/arm-protos.h (arm_output_multireg_pop) New declaration.
 * config/arm/arm.c (arm_output_multireg_pop) New function.
 (arm_emit_multi_reg_pop): New function.
 (ldm_stm_operation_p): Check SP in the register list.
 
 
 2-patterns.patch.txt
 
 


 diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
 index 4717725..9093801 100644
 --- a/gcc/config/arm/arm.c
 +++ b/gcc/config/arm/arm.c
 @@ -13815,6 +13815,84 @@ vfp_output_fldmd (FILE * stream, unsigned int base, 
 int reg, int count)
  }
  
  
 +/* OPERANDS[0] is the entire list of insns that constitute pop,
 +   OPERANDS[1] is the base register, RETURN_PC is true iff return insn
 +   is in the list, UPDATE is true iff the list contains explicit
 +   update of base register.
 + */

Close of comment should not be on a separate line.

 +void
 +arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool 
 reverse,
 + bool update)

 +  offset += return_pc ? 1 : 0;
 +
 +  /* Is the base register in the list? */

Two spaces at end of comment before */.

 +  for (i = offset; i  num_saves; i++)
 +{
 +  regno = REGNO (XEXP (XVECEXP (operands[0], 0, i), 0));
 +  /* If SP is in the list, then the base register must be SP. */

And here.

 +  gcc_assert ((regno != SP_REGNUM) || (regno_base == SP_REGNUM));
 +  /* If base register is in the list, there must be no explicit update.  
 */
 +  if (regno == regno_base)
 +gcc_assert (!update);
 +}
 +
 +  conditional = reverse ? %?%D0 : %?%d0;
 +  if ((regno_base == SP_REGNUM)  TARGET_UNIFIED_ASM)
 +{
 +  /* Output pop (not stmfd) because it has a shorter encoding. */

And here.

 +  gcc_assert (update);
 +  sprintf (pattern, pop%s\t{, conditional);
 +}
 +  else
 +{
 +  /* Output ldmfd when the base register is SP, otherwise output ldmia.
 + It's just a convention, their semantics are identical.  */
 +  if (regno_base == SP_REGNUM)
 +sprintf (pattern, ldm%sfd\t, conditional);
 +  else if (TARGET_UNIFIED_ASM)
 +sprintf (pattern, ldmia%s\t, conditional);
 +  else
 +sprintf (pattern, ldm%sia\t, conditional);
 +
 +  strcat (pattern, reg_names[regno_base]);
 +  if (update)
 +strcat (pattern, !, {);
 +  else
 +strcat (pattern, , {);
 +}
 +
 +  /* Output the first destination register. */

And here.

 diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
 index ed33c9b..862ccf4 100644
 --- a/gcc/config/arm/arm.md
 +++ b/gcc/config/arm/arm.md
 @@ -10959,6 +10959,89 @@
[(set_attr type f_fpa_store)]
  )
  
 +;; Pop (as used in epilogue RTL)
 +;;
 +(define_insn *load_multiple_with_writeback
 +  [(match_parallel 0 load_multiple_operation
 +[(set (match_operand:SI 1 s_register_operand +rk)
 +  (plus:SI (match_dup 1)
 +   (match_operand:SI 2 const_int_operand I)))
 + (set (match_operand:SI 3 s_register_operand =rk)
 +  (mem:SI (match_dup 1)))
 +])]
 +  TARGET_32BIT  (reload_in_progress || reload_completed)
 +  *
 +  {
 +arm_output_multireg_pop (operands, /*return_pc=*/FALSE,
 +   /*cond=*/const_true_rtx,
 +   /*reverse=*/FALSE,
 +   /*update=*/TRUE);

Use lower case for TRUE and FALSE.  Several instances later on as well.

OK with those changes.

R.



[Patch, ARM][2/8] Epilogue in RTL: new patterns for int regs

2012-05-31 Thread Greta Yorsh
This patch adds new define_insn patterns for epilogue with integer
registers.

The patterns can handle pop multiple with writeback and return (loading into
PC directly).
To handle return, the patterns use a new special predicate
pop_multiple_return, that uses ldm_stm_operation_p function from a previous
patch. To output assembly, the patterns use a new function
arm_output_multireg_pop.

This patch also adds a new function arm_emit_multi_reg_pop
that emits RTL that matches the new pop patterns for integer registers.
This is a helper function for epilogue expansion. It is used by a later
patch.

ChangeLog:

gcc

2012-05-31  Ian Bolton  ian.bol...@arm.com
Sameera Deshpande  sameera.deshpa...@arm.com
Greta Yorsh  greta.yo...@arm.com

* config/arm/arm.md (load_multiple_with_writeback) New define_insn.
(load_multiple, pop_multiple_with_writeback_and_return) Likewise.
(pop_multiple_with_return, ldr_with_return) Likewise.
* config/arm/predicates.md (pop_multiple_return) New special
predicate.
* config/arm/arm-protos.h (arm_output_multireg_pop) New declaration.
* config/arm/arm.c (arm_output_multireg_pop) New function.
(arm_emit_multi_reg_pop): New function.
(ldm_stm_operation_p): Check SP in the register list.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 53c2aef..7b25e37 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -156,6 +156,7 @@ extern intarm_emit_vector_const (FILE *, rtx);
 extern void arm_emit_fp16_const (rtx c);
 extern const char * arm_output_load_gr (rtx *);
 extern const char *vfp_output_fstmd (rtx *);
+extern void arm_output_multireg_pop (rtx *, bool, rtx, bool, bool);
 extern void arm_set_return_address (rtx, rtx);
 extern int arm_eliminable_register (rtx);
 extern const char *arm_output_shift(rtx *, int);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 4717725..9093801 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13815,6 +13815,84 @@ vfp_output_fldmd (FILE * stream, unsigned int base, 
int reg, int count)
 }
 
 
+/* OPERANDS[0] is the entire list of insns that constitute pop,
+   OPERANDS[1] is the base register, RETURN_PC is true iff return insn
+   is in the list, UPDATE is true iff the list contains explicit
+   update of base register.
+ */
+void
+arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
+ bool update)
+{
+  int i;
+  char pattern[100];
+  int offset;
+  const char *conditional;
+  int num_saves = XVECLEN (operands[0], 0);
+  unsigned int regno;
+  unsigned int regno_base = REGNO (operands[1]);
+
+  offset = 0;
+  offset += update ? 1 : 0;
+  offset += return_pc ? 1 : 0;
+
+  /* Is the base register in the list? */
+  for (i = offset; i  num_saves; i++)
+{
+  regno = REGNO (XEXP (XVECEXP (operands[0], 0, i), 0));
+  /* If SP is in the list, then the base register must be SP. */
+  gcc_assert ((regno != SP_REGNUM) || (regno_base == SP_REGNUM));
+  /* If base register is in the list, there must be no explicit update.  */
+  if (regno == regno_base)
+gcc_assert (!update);
+}
+
+  conditional = reverse ? %?%D0 : %?%d0;
+  if ((regno_base == SP_REGNUM)  TARGET_UNIFIED_ASM)
+{
+  /* Output pop (not stmfd) because it has a shorter encoding. */
+  gcc_assert (update);
+  sprintf (pattern, pop%s\t{, conditional);
+}
+  else
+{
+  /* Output ldmfd when the base register is SP, otherwise output ldmia.
+ It's just a convention, their semantics are identical.  */
+  if (regno_base == SP_REGNUM)
+sprintf (pattern, ldm%sfd\t, conditional);
+  else if (TARGET_UNIFIED_ASM)
+sprintf (pattern, ldmia%s\t, conditional);
+  else
+sprintf (pattern, ldm%sia\t, conditional);
+
+  strcat (pattern, reg_names[regno_base]);
+  if (update)
+strcat (pattern, !, {);
+  else
+strcat (pattern, , {);
+}
+
+  /* Output the first destination register. */
+  strcat (pattern,
+  reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, offset), 0))]);
+
+  /* Output the rest of the destination registers.  */
+  for (i = offset + 1; i  num_saves; i++)
+{
+  strcat (pattern, , );
+  strcat (pattern,
+  reg_names[REGNO (XEXP (XVECEXP (operands[0], 0, i), 0))]);
+}
+
+  strcat (pattern, });
+
+  if (IS_INTERRUPT (arm_current_func_type ())  return_pc)
+strcat (pattern, ^);
+
+  output_asm_insn (pattern, cond);
+}
+
+
 /* Output the assembly for a store multiple.  */
 
 const char *
@@ -16461,6 +16539,85 @@ emit_multi_reg_push (unsigned long mask)
   return par;
 }
 
+/* Generate and emit an insn pattern that we will recognize as a pop_multi.
+   SAVED_REGS_MASK shows which registers need to be restored.
+
+   Unfortunately, since this insn does not reflect very well the actual
+   semantics of the operation, we need to