diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 694aa28..b79851b 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 fe6902f..f2f3971 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -2156,6 +2156,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 (); } @@ -2501,6 +2509,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 @@ -23341,7 +23361,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; @@ -23354,7 +23374,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 d5fcd50..4f2adee 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -8577,17 +8577,17 @@ [(set_attr "type" "call")] ) -(define_expand "return" - [(return)] +(define_expand "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)" + " " { if (TARGET_THUMB2) { - thumb2_expand_return (); + thumb2_expand_return (); DONE; } } @@ -8612,13 +8612,13 @@ (set_attr "predicable" "yes")] ) -(define_insn "*cond_return" +(define_insn "*cond_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 " "* { if (arm_ccfsm_state == 2) @@ -8626,20 +8626,20 @@ arm_ccfsm_state += 2; return \"\"; } - return output_return_instruction (operands[0], true, false, false); + return output_return_instruction (operands[0], true, false, ); }" [(set_attr "conds" "use") (set_attr "length" "12") (set_attr "type" "load1")] ) -(define_insn "*cond_return_inverted" +(define_insn "*cond_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 " "* { if (arm_ccfsm_state == 2) @@ -8647,7 +8647,7 @@ arm_ccfsm_state += 2; return \"\"; } - return output_return_instruction (operands[0], true, true, false); + return output_return_instruction (operands[0], true, true, ); }" [(set_attr "conds" "use") (set_attr "length" "12") diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index b3ad42b..d84929f 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 0000000..523dc02 --- /dev/null +++ b/gcc/testsuite/gcc.dg/shrink-wrap-alloca.c @@ -0,0 +1,11 @@ +/* { 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 0000000..0a128c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/shrink-wrap-pretend.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g" } */ + +#include +#include +#include + +#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 0000000..6cb2424 --- /dev/null +++ b/gcc/testsuite/gcc.dg/shrink-wrap-sibcall.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g" } */ + +unsigned char a, b, d, f, g; + +int test(); +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(); +}