diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4f0e2591bb91cd49e79a1057fe6dfac0a2b51350..95444f190380a02e66a49a298bdd36d83bfa1c8d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2010-04-27 Bernd Schmidt <bernds@codesourcery.com> + + PR target/40657 + * config/arm/arm.c (thumb1_extra_regs_pushed): New function. + (thumb1_expand_prologue, thumb1_output_function_prologue): Call it + here to determine which regs to push and how much stack to reserve. + 2010-04-27 Jie Zhang <jie@codesourcery.com> * doc/gimple.texi (gimple_statement_with_ops): Remove diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 8d21b8782f028d88c131e783c3a105a80431cb01..72d54736f05f990a540e730f6f51f73fae29e079 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -19402,6 +19402,51 @@ thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to) } } +/* Given the stack offsets and register mask in OFFSETS, decide + how many additional registers to push instead of subtracting + a constant from SP. */ +static int +thumb1_extra_regs_pushed (arm_stack_offsets *offsets) +{ + HOST_WIDE_INT amount = offsets->outgoing_args - offsets->saved_regs; + unsigned long live_regs_mask = offsets->saved_regs_mask; + /* Extract a mask of the ones we can give to the Thumb's push instruction. */ + unsigned long l_mask = live_regs_mask & 0x40ff; + /* Then count how many other high registers will need to be pushed. */ + unsigned long high_regs_pushed = bit_count (live_regs_mask & 0x0f00); + int n_free; + + /* If the stack frame size is 512 exactly, we can save one load + instruction, which should make this a win even when optimizing + for speed. */ + if (!optimize_size && amount != 512) + return 0; + + /* Can't do this if there are high registers to push, or if we + are not going to do a push at all. */ + if (high_regs_pushed != 0 || l_mask == 0) + return 0; + + /* Don't do this if thumb1_expand_prologue wants to emit instructions + between the push and the stack frame allocation. */ + if ((flag_pic && arm_pic_register != INVALID_REGNUM) + || (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)) + return 0; + + for (n_free = 0; n_free < 8 && !(live_regs_mask & 1); live_regs_mask >>= 1) + n_free++; + + if (n_free == 0) + return 0; + gcc_assert (amount / 4 * 4 == amount); + + if (amount >= 512 && (amount - n_free * 4) < 512) + return (amount - 508) / 4; + if (amount <= n_free * 4) + return amount / 4; + return 0; +} + /* Generate the rest of a function's prologue. */ void thumb1_expand_prologue (void) @@ -19438,6 +19483,7 @@ thumb1_expand_prologue (void) stack_pointer_rtx); amount = offsets->outgoing_args - offsets->saved_regs; + amount -= 4 * thumb1_extra_regs_pushed (offsets); if (amount) { if (amount < 512) @@ -19742,7 +19788,11 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) register. */ else if ((l_mask & 0xff) != 0 || (high_regs_pushed == 0 && l_mask)) - thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask); + { + unsigned long mask = l_mask; + mask |= (1 << thumb1_extra_regs_pushed (offsets)) - 1; + thumb_pushpop (f, mask, 1, &cfa_offset, mask); + } if (high_regs_pushed) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 21640d68b03e8c4932075bc3dddd9b71733fb720..e3b7527bec8218ddd5d333186280e13139fcfe4f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-04-27 Bernd Schmidt <bernds@codesourcery.com> + + PR target/40657 + * gcc.target/arm/thumb-stackframe.c: New test. + 2010-04-27 Shujing Zhao <pearly.zhao@oracle.com> * gcc.dg/pr32207.c: Fix typo in expected warning messages. diff --git a/gcc/testsuite/gcc.target/arm/thumb-stackframe.c b/gcc/testsuite/gcc.target/arm/thumb-stackframe.c new file mode 100644 index 0000000000000000000000000000000000000000..f6c78804e91de38f93077329b3a744c993f82771 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/thumb-stackframe.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-mthumb -Os" } */ +/* { dg-require-effective-target arm_thumb1_ok } */ + +extern void bar(int*); +int foo() +{ + int x; + bar(&x); + return x; +} + +/* { dg-final { scan-assembler-not "sub\[\\t \]*sp,\[\\t \]*sp," } } */