aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhenqiang Chen <zhenqiang.chen@linaro.org>2013-06-10 22:08:39 +0000
committerChristophe Lyon <christophe.lyon@linaro.org>2013-06-10 22:08:39 +0000
commit11c3cbf9ee4eabc82b677bd72f6267f8b2cb9781 (patch)
tree3cfeb7661b194a82fea87c88c9a4eee6076be62a
parentf33e107b82d1e1d4a8e34a350cfed80ec1799d19 (diff)
2013-06-06 Zhenqiang Chen <zhenqiang.chen@linaro.org>
Backport from mainline (r199438, r199439) git-svn-id: https://gcc.gnu.org/svn/gcc/branches/linaro/gcc-4_8-branch@199923 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.linaro24
-rw-r--r--gcc/config/arm/arm-protos.h3
-rw-r--r--gcc/config/arm/arm.c140
-rw-r--r--gcc/config/arm/arm.md26
-rw-r--r--gcc/config/arm/iterators.md8
-rw-r--r--gcc/testsuite/gcc.dg/shrink-wrap-alloca.c13
-rw-r--r--gcc/testsuite/gcc.dg/shrink-wrap-pretend.c36
-rw-r--r--gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c26
8 files changed, 243 insertions, 33 deletions
diff --git a/gcc/ChangeLog.linaro b/gcc/ChangeLog.linaro
index e5ef0e34c61..d047e9bc1fb 100644
--- a/gcc/ChangeLog.linaro
+++ b/gcc/ChangeLog.linaro
@@ -1,3 +1,27 @@
+2013-06-06 Zhenqiang Chen <zhenqiang.chen@linaro.org>
+
+ Backport from mainline (r199438, r199439)
+ 2013-05-30 Zhenqiang Chen <zhenqiang.chen@linaro.org>
+
+ * config/arm/arm.c (arm_add_cfa_adjust_cfa_note): New added.
+ (arm_emit_multi_reg_pop): Add REG_CFA_ADJUST_CFA notes.
+ (arm_emit_vfp_multi_reg_pop): Likewise.
+ (thumb2_emit_ldrd_pop): Likewise.
+ (arm_expand_epilogue): Add misc REG_CFA notes.
+ (arm_unwind_emit): Skip REG_CFA_ADJUST_CFA and REG_CFA_RESTORE.
+
+ 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.dg/shrink-wrap-alloca.c: New added.
+ * gcc.dg/shrink-wrap-pretend.c: New added.
+ * gcc.dg/shrink-wrap-sibcall.c: New added.
+
2013-06-06 Kugan Vivekanandarajah <kuganv@linaro.org>
Backport from mainline r198879:
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index c791341f69b..04284177c96 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 5a76f38e16e..4fd3ccc6c50 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -2164,6 +2164,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 ();
}
@@ -2513,6 +2521,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
@@ -17109,6 +17129,19 @@ emit_multi_reg_push (unsigned long mask)
return par;
}
+/* Add a REG_CFA_ADJUST_CFA REG note to INSN.
+ SIZE is the offset to be adjusted.
+ DEST and SRC might be stack_pointer_rtx or hard_frame_pointer_rtx. */
+static void
+arm_add_cfa_adjust_cfa_note (rtx insn, int size, rtx dest, rtx src)
+{
+ rtx dwarf;
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ dwarf = gen_rtx_SET (VOIDmode, dest, plus_constant (Pmode, src, size));
+ add_reg_note (insn, REG_CFA_ADJUST_CFA, dwarf);
+}
+
/* Generate and emit an insn pattern that we will recognize as a pop_multi.
SAVED_REGS_MASK shows which registers need to be restored.
@@ -17199,6 +17232,9 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask)
par = emit_insn (par);
REG_NOTES (par) = dwarf;
+ if (!return_in_pc)
+ arm_add_cfa_adjust_cfa_note (par, UNITS_PER_WORD * num_regs,
+ stack_pointer_rtx, stack_pointer_rtx);
}
/* Generate and emit an insn pattern that we will recognize as a pop_multi
@@ -17269,6 +17305,9 @@ arm_emit_vfp_multi_reg_pop (int first_reg, int num_regs, rtx base_reg)
par = emit_insn (par);
REG_NOTES (par) = dwarf;
+
+ arm_add_cfa_adjust_cfa_note (par, 2 * UNITS_PER_WORD * num_regs,
+ base_reg, base_reg);
}
/* Generate and emit a pattern that will be recognized as LDRD pattern. If even
@@ -17344,6 +17383,7 @@ thumb2_emit_ldrd_pop (unsigned long saved_regs_mask)
pattern can be emitted now. */
par = emit_insn (par);
REG_NOTES (par) = dwarf;
+ RTX_FRAME_RELATED_P (par) = 1;
}
i++;
@@ -17360,7 +17400,12 @@ thumb2_emit_ldrd_pop (unsigned long saved_regs_mask)
stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx, 4 * i));
RTX_FRAME_RELATED_P (tmp) = 1;
- emit_insn (tmp);
+ tmp = emit_insn (tmp);
+ if (!return_in_pc)
+ {
+ arm_add_cfa_adjust_cfa_note (tmp, UNITS_PER_WORD * i,
+ stack_pointer_rtx, stack_pointer_rtx);
+ }
dwarf = NULL_RTX;
@@ -17394,9 +17439,11 @@ thumb2_emit_ldrd_pop (unsigned long saved_regs_mask)
else
{
par = emit_insn (tmp);
+ REG_NOTES (par) = dwarf;
+ arm_add_cfa_adjust_cfa_note (par, UNITS_PER_WORD,
+ stack_pointer_rtx, stack_pointer_rtx);
}
- REG_NOTES (par) = dwarf;
}
else if ((num_regs % 2) == 1 && return_in_pc)
{
@@ -23960,7 +24007,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;
@@ -23973,7 +24020,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)
{
@@ -24251,6 +24298,7 @@ arm_expand_epilogue (bool really_return)
if (frame_pointer_needed)
{
+ rtx insn;
/* Restore stack pointer if necessary. */
if (TARGET_ARM)
{
@@ -24261,9 +24309,12 @@ arm_expand_epilogue (bool really_return)
/* Force out any pending memory operations that reference stacked data
before stack de-allocation occurs. */
emit_insn (gen_blockage ());
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- hard_frame_pointer_rtx,
- GEN_INT (amount)));
+ insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
+ hard_frame_pointer_rtx,
+ GEN_INT (amount)));
+ arm_add_cfa_adjust_cfa_note (insn, amount,
+ stack_pointer_rtx,
+ hard_frame_pointer_rtx);
/* Emit USE(stack_pointer_rtx) to ensure that stack adjustment is not
deleted. */
@@ -24273,16 +24324,25 @@ arm_expand_epilogue (bool really_return)
{
/* In Thumb-2 mode, the frame pointer points to the last saved
register. */
- amount = offsets->locals_base - offsets->saved_regs;
- if (amount)
- emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
- hard_frame_pointer_rtx,
- GEN_INT (amount)));
+ amount = offsets->locals_base - offsets->saved_regs;
+ if (amount)
+ {
+ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+ hard_frame_pointer_rtx,
+ GEN_INT (amount)));
+ arm_add_cfa_adjust_cfa_note (insn, amount,
+ hard_frame_pointer_rtx,
+ hard_frame_pointer_rtx);
+ }
/* Force out any pending memory operations that reference stacked data
before stack de-allocation occurs. */
emit_insn (gen_blockage ());
- emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
+ insn = emit_insn (gen_movsi (stack_pointer_rtx,
+ hard_frame_pointer_rtx));
+ arm_add_cfa_adjust_cfa_note (insn, 0,
+ stack_pointer_rtx,
+ hard_frame_pointer_rtx);
/* Emit USE(stack_pointer_rtx) to ensure that stack adjustment is not
deleted. */
emit_insn (gen_force_register_use (stack_pointer_rtx));
@@ -24295,12 +24355,15 @@ arm_expand_epilogue (bool really_return)
amount = offsets->outgoing_args - offsets->saved_regs;
if (amount)
{
+ rtx tmp;
/* Force out any pending memory operations that reference stacked data
before stack de-allocation occurs. */
emit_insn (gen_blockage ());
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT (amount)));
+ tmp = emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (amount)));
+ arm_add_cfa_adjust_cfa_note (tmp, amount,
+ stack_pointer_rtx, stack_pointer_rtx);
/* Emit USE(stack_pointer_rtx) to ensure that stack adjustment is
not deleted. */
emit_insn (gen_force_register_use (stack_pointer_rtx));
@@ -24353,6 +24416,8 @@ arm_expand_epilogue (bool really_return)
REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE,
gen_rtx_REG (V2SImode, i),
NULL_RTX);
+ arm_add_cfa_adjust_cfa_note (insn, UNITS_PER_WORD,
+ stack_pointer_rtx, stack_pointer_rtx);
}
if (saved_regs_mask)
@@ -24400,6 +24465,9 @@ arm_expand_epilogue (bool really_return)
REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE,
gen_rtx_REG (SImode, i),
NULL_RTX);
+ arm_add_cfa_adjust_cfa_note (insn, UNITS_PER_WORD,
+ stack_pointer_rtx,
+ stack_pointer_rtx);
}
}
}
@@ -24424,9 +24492,33 @@ arm_expand_epilogue (bool really_return)
}
if (crtl->args.pretend_args_size)
- emit_insn (gen_addsi3 (stack_pointer_rtx,
- stack_pointer_rtx,
- GEN_INT (crtl->args.pretend_args_size)));
+ {
+ int i, j;
+ rtx dwarf = NULL_RTX;
+ rtx tmp = emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (crtl->args.pretend_args_size)));
+
+ RTX_FRAME_RELATED_P (tmp) = 1;
+
+ if (cfun->machine->uses_anonymous_args)
+ {
+ /* Restore pretend args. Refer arm_expand_prologue on how to save
+ pretend_args in stack. */
+ int num_regs = crtl->args.pretend_args_size / 4;
+ saved_regs_mask = (0xf0 >> num_regs) & 0xf;
+ for (j = 0, i = 0; j < num_regs; i++)
+ if (saved_regs_mask & (1 << i))
+ {
+ rtx reg = gen_rtx_REG (SImode, i);
+ dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
+ j++;
+ }
+ REG_NOTES (tmp) = dwarf;
+ }
+ arm_add_cfa_adjust_cfa_note (tmp, crtl->args.pretend_args_size,
+ stack_pointer_rtx, stack_pointer_rtx);
+ }
if (!really_return)
return;
@@ -26094,9 +26186,17 @@ arm_unwind_emit (FILE * asm_out_file, rtx insn)
handled_one = true;
break;
+ /* The INSN is generated in epilogue. It is set as RTX_FRAME_RELATED_P
+ to get correct dwarf information for shrink-wrap. We should not
+ emit unwind information for it because these are used either for
+ pretend arguments or notes to adjust sp and restore registers from
+ stack. */
+ case REG_CFA_ADJUST_CFA:
+ case REG_CFA_RESTORE:
+ return;
+
case REG_CFA_DEF_CFA:
case REG_CFA_EXPRESSION:
- case REG_CFA_ADJUST_CFA:
case REG_CFA_OFFSET:
/* ??? Only handling here what we actually emit. */
gcc_unreachable ();
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 47be5aa3e3d..86127119731 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -9257,17 +9257,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;
}
}
@@ -9292,13 +9292,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)
@@ -9306,20 +9306,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)
@@ -9327,7 +9328,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 b3ad42b376f..d84929f3d1f 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/gcc.dg/shrink-wrap-alloca.c b/gcc/testsuite/gcc.dg/shrink-wrap-alloca.c
new file mode 100644
index 00000000000..9e69ca16645
--- /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 00000000000..6e20ca12e98
--- /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 00000000000..193bec2ce69
--- /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 ();
+}