+2010-05-24 Paul Brook <paul@codesourcery.com>
+
+ * gengtype-lex.l: Add HARD_REG_SET.
+ * expr.c (expand_expr_real_1): Record writes to hard registers.
+ * function.c (rtl_data): Add asm_clobbers.
+ * ira.c (compute_regs_asm_clobbered): Use crtl->asm_clobbers.
+ (ira_setup_eliminable_regset): Remove regs_asm_clobbered.
+ Use crtl->asm_clobbers.
+
2010-05-24 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
* doc/makefile.texi (Makefile): Mention stages 'profile'
expand_decl_rtl:
gcc_assert (decl_rtl);
decl_rtl = copy_rtx (decl_rtl);
+ /* Record writes to register variables. */
+ if (modifier == EXPAND_WRITE && REG_P (decl_rtl)
+ && REGNO (decl_rtl) < FIRST_PSEUDO_REGISTER)
+ {
+ int i = REGNO (decl_rtl);
+ int nregs = hard_regno_nregs[i][GET_MODE (decl_rtl)];
+ while (nregs)
+ {
+ SET_HARD_REG_BIT (crtl->asm_clobbers, i);
+ i++;
+ nregs--;
+ }
+ }
/* Ensure variable marked as used even if it doesn't go through
a parser. If it hasn't be used yet, write out an external
#include "hashtab.h"
#include "vecprim.h"
#include "tm.h" /* For CUMULATIVE_ARGS. */
+#include "hard-reg-set.h"
/* Stack of pending (incomplete) sequences saved by `start_sequence'.
Each element describes one pending sequence.
TREE_NOTHROW (current_function_decl) it is set even for overwritable
function where currently compiled version of it is nothrow. */
bool nothrow;
+
+ /* Like regs_ever_live, but 1 if a reg is set or clobbered from an
+ asm. Unlike regs_ever_live, elements of this array corresponding
+ to eliminable regs (like the frame pointer) are set if an asm
+ sets them. */
+ HARD_REG_SET asm_clobbers;
};
#define return_label (crtl->x_return_label)
ID [[:alpha:]_][[:alnum:]_]*
WS [[:space:]]+
HWS [ \t\r\v\f]*
-IWORD short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD|CPPCHAR_SIGNED_T|ino_t|dev_t
+IWORD short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD|CPPCHAR_SIGNED_T|ino_t|dev_t|HARD_REG_SET
ITYPE {IWORD}({WS}{IWORD})*
EOID [^[:alnum:]_]
return for_each_rtx (&insn, insn_contains_asm_1, NULL);
}
-/* Set up regs_asm_clobbered. */
+/* Add register clobbers from asm statements. */
static void
-compute_regs_asm_clobbered (char *regs_asm_clobbered)
+compute_regs_asm_clobbered (void)
{
basic_block bb;
- memset (regs_asm_clobbered, 0, sizeof (char) * FIRST_PSEUDO_REGISTER);
-
FOR_EACH_BB (bb)
{
rtx insn;
+ hard_regno_nregs[dregno][mode] - 1;
for (i = dregno; i <= end; ++i)
- regs_asm_clobbered[i] = 1;
+ SET_HARD_REG_BIT(crtl->asm_clobbers, i);
}
}
}
void
ira_setup_eliminable_regset (void)
{
- /* Like regs_ever_live, but 1 if a reg is set or clobbered from an
- asm. Unlike regs_ever_live, elements of this array corresponding
- to eliminable regs (like the frame pointer) are set if an asm
- sets them. */
- char *regs_asm_clobbered
- = (char *) alloca (FIRST_PSEUDO_REGISTER * sizeof (char));
#ifdef ELIMINABLE_REGS
int i;
static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
COPY_HARD_REG_SET (ira_no_alloc_regs, no_unit_alloc_regs);
CLEAR_HARD_REG_SET (eliminable_regset);
- compute_regs_asm_clobbered (regs_asm_clobbered);
+ compute_regs_asm_clobbered ();
+
/* Build the regset of all eliminable registers and show we can't
use those that we already know won't be eliminated. */
#ifdef ELIMINABLE_REGS
= (! targetm.can_eliminate (eliminables[i].from, eliminables[i].to)
|| (eliminables[i].to == STACK_POINTER_REGNUM && need_fp));
- if (! regs_asm_clobbered[eliminables[i].from])
+ if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, eliminables[i].from))
{
SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
df_set_regs_ever_live (eliminables[i].from, true);
}
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- if (! regs_asm_clobbered[HARD_FRAME_POINTER_REGNUM])
+ if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
{
SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
if (need_fp)
#endif
#else
- if (! regs_asm_clobbered[FRAME_POINTER_REGNUM])
+ if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
{
SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
if (need_fp)
+2010-05-24 Paul Brook <paul@codesourcery.com>
+
+ * gcc.target/arm/frame-pointer-1.c: New test.
+ * gcc.target/i386/pr9771-1.c: Move code out of main to allow frame
+ pointer elimination.
+
2010-05-23 H.J. Lu <hongjiu.lu@intel.com>
PR target/44245
--- /dev/null
+/* Check local register variables using a register conventionally
+ used as the frame pointer aren't clobbered under high register pressure. */
+/* { dg-do run } */
+/* { dg-options "-Os -mthumb -fomit-frame-pointer" } */
+
+#include <stdlib.h>
+
+int global=5;
+
+void __attribute__((noinline)) foo(int p1, int p2, int p3, int p4)
+{
+ if (global != 5 || p1 != 1 || p2 != 2 || p3 != 3 || p4 != 4)
+ abort();
+}
+
+int __attribute__((noinline)) test(int a, int b, int c, int d)
+{
+ register unsigned long r __asm__("r7") = 0xdeadbeef;
+ int e;
+
+ /* ABCD are live after the call which should be enough
+ to cause r7 to be used if it weren't for the register variable. */
+ foo(a,b,c,d);
+
+ e = 0;
+ __asm__ __volatile__ ("mov %0, %2"
+ : "=r" (e)
+ : "0" (e), "r" (r));
+
+ global = a+b+c+d;
+
+ return e;
+}
+
+int main()
+{
+ if (test(1, 2, 3, 4) != 0xdeadbeef)
+ abort();
+ if (global != 10)
+ abort();
+ return 0;
+}
*adr = save;
}
-int main()
+/* This must not be inlined becuase main() requires the frame pointer
+ for stack alignment. */
+void test(void) __attribute__((noinline));
+void test(void)
{
B = &x;
exit(0);
}
+int main()
+{
+ test();
+ return 0;
+
+}