From 24d5b0970a7d07a30430b17b2a837832c3b1b38e Mon Sep 17 00:00:00 2001
From: Xuepeng Guo <xguo@gcc.gnu.org>
Date: Thu, 30 May 2013 08:11:30 +0000
Subject: [PATCH] arm-protos.h: Add and update function protos.

gcc/ChangeLog:
2013-05-30  Bernd Schmidt  <bernds@codesourcery.com>
	    Zhenqiang Chen  <zhenqiang.chen@linaro.org>

	* config/arm/arm-protos.h: Add and update function protos.
	* config/arm/arm.c (use_simple_return_p): New added.
	(thumb2_expand_return): Check simple_return flag.
	* config/arm/arm.md: Add simple_return and conditional simple_return.
	* config/arm/iterators.md: Add iterator for return and simple_return.

gcc/testsuite/ChangeLog:
2013-05-30  Zhenqiang Chen  <zhenqiang.chen@linaro.org>

	* gcc.dg/shrink-wrap-alloca.c: New added.
	* gcc.dg/shrink-wrap-pretend.c: New added.
	* gcc.dg/shrink-wrap-sibcall.c: New added.

From-SVN: r199439
---
 gcc/ChangeLog                              |  9 ++++++
 gcc/config/arm/arm-protos.h                |  3 +-
 gcc/config/arm/arm.c                       | 24 +++++++++++++--
 gcc/config/arm/arm.md                      | 26 ++++++++--------
 gcc/config/arm/iterators.md                |  8 +++++
 gcc/testsuite/ChangeLog                    |  6 ++++
 gcc/testsuite/gcc.dg/shrink-wrap-alloca.c  | 13 ++++++++
 gcc/testsuite/gcc.dg/shrink-wrap-pretend.c | 36 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c | 26 ++++++++++++++++
 9 files changed, 136 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/shrink-wrap-alloca.c
 create mode 100644 gcc/testsuite/gcc.dg/shrink-wrap-pretend.c
 create mode 100644 gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 963403d5ced3..6d540e759e41 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2013-05-30  Bernd Schmidt  <bernds@codesourcery.com>
+	    Zhenqiang Chen  <zhenqiang.chen@linaro.org>
+
+	* config/arm/arm-protos.h: Add and update function protos.
+	* config/arm/arm.c (use_simple_return_p): New added.
+	(thumb2_expand_return): Check simple_return flag.
+	* config/arm/arm.md: Add simple_return and conditional simple_return.
+	* config/arm/iterators.md: Add iterator for return and simple_return.
+
 2013-05-30  Zhenqiang Chen  <zhenqiang.chen@linaro.org>
 
 	* config/arm/arm.c (arm_add_cfa_adjust_cfa_note): New added.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index c791341f69b8..04284177c962 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -24,12 +24,13 @@
 
 extern enum unwind_info_type arm_except_unwind_info (struct gcc_options *);
 extern int use_return_insn (int, rtx);
+extern bool use_simple_return_p (void);
 extern enum reg_class arm_regno_class (int);
 extern void arm_load_pic_register (unsigned long);
 extern int arm_volatile_func (void);
 extern void arm_expand_prologue (void);
 extern void arm_expand_epilogue (bool);
-extern void thumb2_expand_return (void);
+extern void thumb2_expand_return (bool);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
 extern void thumb2_asm_output_opcode (FILE *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index ac41d93ae1e4..55a512349cca 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -2169,6 +2169,14 @@ arm_option_override (void)
                          global_options.x_param_values,
                          global_options_set.x_param_values);
 
+  /* Disable shrink-wrap when optimizing function for size, since it tends to
+     generate additional returns.  */
+  if (optimize_function_for_size_p (cfun) && TARGET_THUMB2)
+    flag_shrink_wrap = false;
+  /* TBD: Dwarf info for apcs frame is not handled yet.  */
+  if (TARGET_APCS_FRAME)
+    flag_shrink_wrap = false;
+
   /* Register global variables with the garbage collector.  */
   arm_add_gc_roots ();
 }
@@ -2518,6 +2526,18 @@ use_return_insn (int iscond, rtx sibling)
   return 1;
 }
 
+/* Return TRUE if we should try to use a simple_return insn, i.e. perform
+   shrink-wrapping if possible.  This is the case if we need to emit a
+   prologue, which we can test by looking at the offsets.  */
+bool
+use_simple_return_p (void)
+{
+  arm_stack_offsets *offsets;
+
+  offsets = arm_get_frame_offsets ();
+  return offsets->outgoing_args != 0;
+}
+
 /* Return TRUE if int I is a valid immediate ARM constant.  */
 
 int
@@ -24035,7 +24055,7 @@ thumb1_expand_prologue (void)
    all we really need to check here is if single register is to be
    returned, or multiple register return.  */
 void
-thumb2_expand_return (void)
+thumb2_expand_return (bool simple_return)
 {
   int i, num_regs;
   unsigned long saved_regs_mask;
@@ -24048,7 +24068,7 @@ thumb2_expand_return (void)
     if (saved_regs_mask & (1 << i))
       num_regs++;
 
-  if (saved_regs_mask)
+  if (!simple_return && saved_regs_mask)
     {
       if (num_regs == 1)
         {
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 4b45c984bf43..b7db3616cdf9 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -9276,17 +9276,17 @@
   [(set_attr "type" "call")]
 )
 
-(define_expand "return"
-  [(return)]
+(define_expand "<return_str>return"
+  [(returns)]
   "(TARGET_ARM || (TARGET_THUMB2
                    && ARM_FUNC_TYPE (arm_current_func_type ()) == ARM_FT_NORMAL
                    && !IS_STACKALIGN (arm_current_func_type ())))
-    && USE_RETURN_INSN (FALSE)"
+    <return_cond_false>"
   "
   {
     if (TARGET_THUMB2)
       {
-        thumb2_expand_return ();
+        thumb2_expand_return (<return_simple_p>);
         DONE;
       }
   }
@@ -9311,13 +9311,13 @@
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "*cond_return"
+(define_insn "*cond_<return_str>return"
   [(set (pc)
         (if_then_else (match_operator 0 "arm_comparison_operator"
 		       [(match_operand 1 "cc_register" "") (const_int 0)])
-                      (return)
+                      (returns)
                       (pc)))]
-  "TARGET_ARM && USE_RETURN_INSN (TRUE)"
+  "TARGET_ARM  <return_cond_true>"
   "*
   {
     if (arm_ccfsm_state == 2)
@@ -9325,20 +9325,21 @@
         arm_ccfsm_state += 2;
         return \"\";
       }
-    return output_return_instruction (operands[0], true, false, false);
+    return output_return_instruction (operands[0], true, false,
+				      <return_simple_p>);
   }"
   [(set_attr "conds" "use")
    (set_attr "length" "12")
    (set_attr "type" "load1")]
 )
 
-(define_insn "*cond_return_inverted"
+(define_insn "*cond_<return_str>return_inverted"
   [(set (pc)
         (if_then_else (match_operator 0 "arm_comparison_operator"
 		       [(match_operand 1 "cc_register" "") (const_int 0)])
                       (pc)
-		      (return)))]
-  "TARGET_ARM && USE_RETURN_INSN (TRUE)"
+		      (returns)))]
+  "TARGET_ARM <return_cond_true>"
   "*
   {
     if (arm_ccfsm_state == 2)
@@ -9346,7 +9347,8 @@
         arm_ccfsm_state += 2;
         return \"\";
       }
-    return output_return_instruction (operands[0], true, true, false);
+    return output_return_instruction (operands[0], true, true,
+				      <return_simple_p>);
   }"
   [(set_attr "conds" "use")
    (set_attr "length" "12")
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index b3ad42b376f8..d84929f3d1fb 100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -496,3 +496,11 @@
 (define_int_attr nvrint_variant [(UNSPEC_NVRINTZ "z") (UNSPEC_NVRINTP "p")
                                 (UNSPEC_NVRINTA "a") (UNSPEC_NVRINTM "m")
                                 (UNSPEC_NVRINTX "x") (UNSPEC_NVRINTN "n")])
+;; Both kinds of return insn.
+(define_code_iterator returns [return simple_return])
+(define_code_attr return_str [(return "") (simple_return "simple_")])
+(define_code_attr return_simple_p [(return "false") (simple_return "true")])
+(define_code_attr return_cond_false [(return " && USE_RETURN_INSN (FALSE)")
+                               (simple_return " && use_simple_return_p ()")])
+(define_code_attr return_cond_true [(return " && USE_RETURN_INSN (TRUE)")
+                               (simple_return " && use_simple_return_p ()")])
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d51376dff397..6af715564c9a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2013-05-30  Zhenqiang Chen  <zhenqiang.chen@linaro.org>
+
+	* gcc.dg/shrink-wrap-alloca.c: New added.
+	* gcc.dg/shrink-wrap-pretend.c: New added.
+	* gcc.dg/shrink-wrap-sibcall.c: New added.
+
 2013-05-30  Tobias Burnus  <burnus@net-b.de>
 
 	PR fortran/57458
diff --git a/gcc/testsuite/gcc.dg/shrink-wrap-alloca.c b/gcc/testsuite/gcc.dg/shrink-wrap-alloca.c
new file mode 100644
index 000000000000..9e69ca166458
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/shrink-wrap-alloca.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -g" } */
+
+extern int * alloca (int);
+
+int *p;
+
+void
+test (int a)
+{
+  if (a > 0)
+    p = alloca (4);
+}
diff --git a/gcc/testsuite/gcc.dg/shrink-wrap-pretend.c b/gcc/testsuite/gcc.dg/shrink-wrap-pretend.c
new file mode 100644
index 000000000000..6e20ca12e98d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/shrink-wrap-pretend.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -g" } */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#define DEBUG_BUFFER_SIZE 80
+int unifi_debug = 5;
+
+void
+unifi_trace (void* ospriv, int level, const char *fmt, ...)
+{
+   static char s[DEBUG_BUFFER_SIZE];
+   va_list args;
+   unsigned int len;
+
+   if (!ospriv)
+     return;
+
+   if (unifi_debug >= level)
+     {
+       va_start (args, fmt);
+       len = vsnprintf (&(s)[0], (DEBUG_BUFFER_SIZE), fmt, args);
+       va_end (args);
+
+       if (len >= DEBUG_BUFFER_SIZE)
+	 {
+	   (s)[DEBUG_BUFFER_SIZE - 2] = '\n';
+	   (s)[DEBUG_BUFFER_SIZE - 1] = 0;
+	 }
+
+       printf ("%s", s);
+     }
+}
+
diff --git a/gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c b/gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c
new file mode 100644
index 000000000000..193bec2ce697
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -g" } */
+
+unsigned char a, b, d, f, g;
+
+int test (void);
+
+int
+baz (int c)
+{
+  if (c == 0) return test ();
+  if (b & 1)
+    {
+      g = 0;
+      int e = (a & 0x0f) - (g & 0x0f);
+
+      if (!a)  b |= 0x80;
+      a = e + test ();
+     f = g/5 + a*3879 + b *2985;
+    }
+   else
+   {
+     f = g + a*39879 + b *25;
+   }
+  return test ();
+}
-- 
GitLab