diff options
-rw-r--r-- | gcc/ChangeLog.linaro | 24 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 140 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 26 | ||||
-rw-r--r-- | gcc/config/arm/iterators.md | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/shrink-wrap-alloca.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/shrink-wrap-pretend.c | 36 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c | 26 |
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 (); +} |