This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Don't lose asm sets of frame pointer
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 25 Nov 2003 01:49:51 +1030
- Subject: Don't lose asm sets of frame pointer
This fixes PR 13169, so that global_alloc now sees all regs set or
clobbered by asm statements. Previously, we had the situation that not
all regs set in an asm were noticed in regs_ever_live. In particular, a
set of the frame pointer isn't marked, but asms ought to be able to use
the frame pointer reg when -fomit-frame-pointer and other requirements
like no alloca in the function are met. On ppc, we also have a curious
fudge in ELIMINABLE_REGS with r30 being "eliminated" to itself, which
made r30 dangerous to use in an asm. See the PR for more details on
what currently happens.
PR 13169
* basic-block.h (PROP_ASM_SCAN): Define.
* final.c (regs_asm_clobbered): New array.
* regs.h (regs_asm_clobbered): Declare.
* flow.c (life_analysis): Init it.
(mark_set_regs): Set PROP_ASM_SCAN for asms.
(mark_set_1): Set regs_asm_clobbered.
* global.c (global_alloc): Don't set eliminable_regset when
regs_asm_clobbered.
Bootstrapped and tested on the 3.3 branch. Mainline regression test in
progress.
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/basic-block.h gcc-ppc64-34/gcc/basic-block.h
--- gcc-ppc64-34.orig/gcc/basic-block.h 2003-07-19 22:50:33.000000000 +0930
+++ gcc-ppc64-34/gcc/basic-block.h 2003-11-25 00:51:13.000000000 +1030
@@ -477,6 +477,8 @@ enum update_life_extent
#define PROP_AUTOINC 64 /* Create autoinc mem references. */
#define PROP_EQUAL_NOTES 128 /* Take into account REG_EQUAL notes. */
#define PROP_SCAN_DEAD_STORES 256 /* Scan for dead code. */
+#define PROP_ASM_SCAN 512 /* Internal flag used within flow.c
+ to flag analysis of asms. */
#define PROP_FINAL (PROP_DEATH_NOTES | PROP_LOG_LINKS \
| PROP_REG_INFO | PROP_KILL_DEAD_CODE \
| PROP_SCAN_DEAD_CODE | PROP_AUTOINC \
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/final.c gcc-ppc64-34/gcc/final.c
--- gcc-ppc64-34.orig/gcc/final.c 2003-11-01 11:13:55.000000000 +1030
+++ gcc-ppc64-34/gcc/final.c 2003-11-25 00:29:46.000000000 +1030
@@ -170,6 +170,12 @@ CC_STATUS cc_prev_status;
char regs_ever_live[FIRST_PSEUDO_REGISTER];
+/* 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[FIRST_PSEUDO_REGISTER];
+
/* Nonzero means current function must be given a frame pointer.
Set in stmt.c if anything is allocated on the stack there.
Set in reload1.c if anything is allocated on the stack there. */
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/flow.c gcc-ppc64-34/gcc/flow.c
--- gcc-ppc64-34.orig/gcc/flow.c 2003-11-25 00:17:41.000000000 +1030
+++ gcc-ppc64-34/gcc/flow.c 2003-11-25 00:29:46.000000000 +1030
@@ -463,7 +463,10 @@ life_analysis (rtx f, FILE *file, int fl
is not immediately handy. */
if (flags & PROP_REG_INFO)
- memset (regs_ever_live, 0, sizeof (regs_ever_live));
+ {
+ memset (regs_ever_live, 0, sizeof (regs_ever_live));
+ memset (regs_asm_clobbered, 0, sizeof (regs_asm_clobbered));
+ }
update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
/* Clean up. */
@@ -2444,6 +2447,7 @@ mark_set_regs (struct propagate_block_in
rtx cond = NULL_RTX;
rtx link;
enum rtx_code code;
+ int flags = pbi->flags;
if (insn)
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
@@ -2452,14 +2456,17 @@ mark_set_regs (struct propagate_block_in
mark_set_1 (pbi, SET, XEXP (link, 0),
(GET_CODE (x) == COND_EXEC
? COND_EXEC_TEST (x) : NULL_RTX),
- insn, pbi->flags);
+ insn, flags);
}
retry:
switch (code = GET_CODE (x))
{
case SET:
+ if (GET_CODE (XEXP (x, 1)) == ASM_OPERANDS)
+ flags |= PROP_ASM_SCAN;
+ /* Fall thru */
case CLOBBER:
- mark_set_1 (pbi, code, SET_DEST (x), cond, insn, pbi->flags);
+ mark_set_1 (pbi, code, SET_DEST (x), cond, insn, flags);
return;
case COND_EXEC:
@@ -2482,13 +2489,20 @@ mark_set_regs (struct propagate_block_in
cond = COND_EXEC_TEST (sub);
sub = COND_EXEC_CODE (sub);
- if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER)
- break;
- /* Fall through. */
+ if (GET_CODE (sub) == SET)
+ goto mark_set;
+ if (GET_CODE (sub) == CLOBBER)
+ goto mark_clob;
+ break;
case SET:
+ mark_set:
+ if (GET_CODE (XEXP (sub, 1)) == ASM_OPERANDS)
+ flags |= PROP_ASM_SCAN;
+ /* Fall thru */
case CLOBBER:
- mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, pbi->flags);
+ mark_clob:
+ mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, flags);
break;
default:
@@ -2712,6 +2726,9 @@ mark_set_1 (struct propagate_block_info
{
for (i = regno_first; i <= regno_last; i++)
regs_ever_live[i] = 1;
+ if (flags & PROP_ASM_SCAN)
+ for (i = regno_first; i <= regno_last; i++)
+ regs_asm_clobbered[i] = 1;
}
else
{
@@ -2797,6 +2814,14 @@ mark_set_1 (struct propagate_block_info
{
if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
pbi->reg_next_use[regno_first] = 0;
+
+ if ((flags & PROP_REG_INFO) != 0
+ && (flags & PROP_ASM_SCAN) != 0
+ && regno_first < FIRST_PSEUDO_REGISTER)
+ {
+ for (i = regno_first; i <= regno_last; i++)
+ regs_asm_clobbered[i] = 1;
+ }
}
/* If this is the last pass and this is a SCRATCH, show it will be dying
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/global.c gcc-ppc64-34/gcc/global.c
--- gcc-ppc64-34.orig/gcc/global.c 2003-07-20 13:40:21.000000000 +0930
+++ gcc-ppc64-34/gcc/global.c 2003-11-25 00:29:46.000000000 +1030
@@ -342,23 +342,30 @@ global_alloc (FILE *file)
that we already know won't be eliminated. */
#ifdef ELIMINABLE_REGS
for (i = 0; i < ARRAY_SIZE (eliminables); i++)
- {
- SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
+ if (!regs_asm_clobbered[eliminables[i].from])
+ {
+ SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
- if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
- || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
- SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
- }
+ if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
+ || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
+ SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
+ }
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
- if (need_fp)
- SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+ if (!regs_asm_clobbered[HARD_FRAME_POINTER_REGNUM])
+ {
+ SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
+ if (need_fp)
+ SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+ }
#endif
#else
- SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
- if (need_fp)
- SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
+ if (!regs_asm_clobbered[FRAME_POINTER_REGNUM])
+ {
+ SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
+ if (need_fp)
+ SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
+ }
#endif
/* Track which registers have already been used. Start with registers
diff -urpN -xCVS -x'*~' -x'*.info*' -x'*.[17]' -xTAGS gcc-ppc64-34.orig/gcc/regs.h gcc-ppc64-34/gcc/regs.h
--- gcc-ppc64-34.orig/gcc/regs.h 2003-07-14 14:07:26.000000000 +0930
+++ gcc-ppc64-34/gcc/regs.h 2003-11-25 00:30:50.000000000 +1030
@@ -153,11 +153,14 @@ extern bitmap_head subregs_of_mode;
extern short *reg_renumber;
-/* Vector indexed by hardware reg
- saying whether that reg is ever used. */
+/* Vector indexed by hardware reg saying whether that reg is ever used. */
extern char regs_ever_live[FIRST_PSEUDO_REGISTER];
+/* Like regs_ever_live, but saying whether reg is set by asm statements. */
+
+extern char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
+
/* For each hard register, the widest mode object that it can contain.
This will be a MODE_INT mode if the register can hold integers. Otherwise
it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
--
Alan Modra
IBM OzLabs - Linux Technology Centre