Commit df2ef49b by Alan Modra Committed by Alan Modra

re PR rtl-optimization/13169 (asm using r30 or r31 confuses global_alloc)

	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.

From-SVN: r74363
parent 929a3294
2003-12-06 Alan Modra <amodra@bigpond.net.au>
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.
2003-12-05 Mark Mitchell <mark@codesourcery.com> 2003-12-05 Mark Mitchell <mark@codesourcery.com>
* config/ia64/ia64.h (MUST_PASS_IN_STACK): Define. * config/ia64/ia64.h (MUST_PASS_IN_STACK): Define.
......
...@@ -477,6 +477,8 @@ enum update_life_extent ...@@ -477,6 +477,8 @@ enum update_life_extent
#define PROP_AUTOINC 64 /* Create autoinc mem references. */ #define PROP_AUTOINC 64 /* Create autoinc mem references. */
#define PROP_EQUAL_NOTES 128 /* Take into account REG_EQUAL notes. */ #define PROP_EQUAL_NOTES 128 /* Take into account REG_EQUAL notes. */
#define PROP_SCAN_DEAD_STORES 256 /* Scan for dead code. */ #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 \ #define PROP_FINAL (PROP_DEATH_NOTES | PROP_LOG_LINKS \
| PROP_REG_INFO | PROP_KILL_DEAD_CODE \ | PROP_REG_INFO | PROP_KILL_DEAD_CODE \
| PROP_SCAN_DEAD_CODE | PROP_AUTOINC \ | PROP_SCAN_DEAD_CODE | PROP_AUTOINC \
......
...@@ -170,6 +170,12 @@ CC_STATUS cc_prev_status; ...@@ -170,6 +170,12 @@ CC_STATUS cc_prev_status;
char regs_ever_live[FIRST_PSEUDO_REGISTER]; 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. /* Nonzero means current function must be given a frame pointer.
Initialized in function.c to 0. Set only in reload1.c as per Initialized in function.c to 0. Set only in reload1.c as per
the needs of the function. */ the needs of the function. */
......
...@@ -464,7 +464,10 @@ life_analysis (rtx f, FILE *file, int flags) ...@@ -464,7 +464,10 @@ life_analysis (rtx f, FILE *file, int flags)
is not immediately handy. */ is not immediately handy. */
if (flags & PROP_REG_INFO) 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); update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
/* Clean up. */ /* Clean up. */
...@@ -2445,6 +2448,7 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn) ...@@ -2445,6 +2448,7 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
rtx cond = NULL_RTX; rtx cond = NULL_RTX;
rtx link; rtx link;
enum rtx_code code; enum rtx_code code;
int flags = pbi->flags;
if (insn) if (insn)
for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
...@@ -2453,14 +2457,17 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn) ...@@ -2453,14 +2457,17 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
mark_set_1 (pbi, SET, XEXP (link, 0), mark_set_1 (pbi, SET, XEXP (link, 0),
(GET_CODE (x) == COND_EXEC (GET_CODE (x) == COND_EXEC
? COND_EXEC_TEST (x) : NULL_RTX), ? COND_EXEC_TEST (x) : NULL_RTX),
insn, pbi->flags); insn, flags);
} }
retry: retry:
switch (code = GET_CODE (x)) switch (code = GET_CODE (x))
{ {
case SET: case SET:
if (GET_CODE (XEXP (x, 1)) == ASM_OPERANDS)
flags |= PROP_ASM_SCAN;
/* Fall thru */
case CLOBBER: 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; return;
case COND_EXEC: case COND_EXEC:
...@@ -2483,13 +2490,20 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn) ...@@ -2483,13 +2490,20 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn)
cond = COND_EXEC_TEST (sub); cond = COND_EXEC_TEST (sub);
sub = COND_EXEC_CODE (sub); sub = COND_EXEC_CODE (sub);
if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER) if (GET_CODE (sub) == SET)
break; goto mark_set;
/* Fall through. */ if (GET_CODE (sub) == CLOBBER)
goto mark_clob;
break;
case SET: case SET:
mark_set:
if (GET_CODE (XEXP (sub, 1)) == ASM_OPERANDS)
flags |= PROP_ASM_SCAN;
/* Fall thru */
case CLOBBER: 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; break;
default: default:
...@@ -2713,6 +2727,9 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c ...@@ -2713,6 +2727,9 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
{ {
for (i = regno_first; i <= regno_last; i++) for (i = regno_first; i <= regno_last; i++)
regs_ever_live[i] = 1; regs_ever_live[i] = 1;
if (flags & PROP_ASM_SCAN)
for (i = regno_first; i <= regno_last; i++)
regs_asm_clobbered[i] = 1;
} }
else else
{ {
...@@ -2798,6 +2815,14 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c ...@@ -2798,6 +2815,14 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
{ {
if (flags & (PROP_LOG_LINKS | PROP_AUTOINC)) if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
pbi->reg_next_use[regno_first] = 0; 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 /* If this is the last pass and this is a SCRATCH, show it will be dying
......
...@@ -343,22 +343,42 @@ global_alloc (FILE *file) ...@@ -343,22 +343,42 @@ global_alloc (FILE *file)
#ifdef ELIMINABLE_REGS #ifdef ELIMINABLE_REGS
for (i = 0; i < ARRAY_SIZE (eliminables); i++) for (i = 0; i < ARRAY_SIZE (eliminables); i++)
{ {
SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from); bool cannot_elim
= (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
|| (eliminables[i].to == STACK_POINTER_REGNUM && need_fp));
if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to) if (!regs_asm_clobbered[eliminables[i].from])
|| (eliminables[i].to == STACK_POINTER_REGNUM && need_fp)) {
SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from); SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
if (cannot_elim)
SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
}
else if (cannot_elim)
error ("%s cannot be used in asm here",
reg_names[eliminables[i].from]);
} }
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM); if (!regs_asm_clobbered[HARD_FRAME_POINTER_REGNUM])
if (need_fp) {
SET_HARD_REG_BIT (no_global_alloc_regs, 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);
}
else if (need_fp)
error ("%s cannot be used in asm here",
reg_names[HARD_FRAME_POINTER_REGNUM]);
#endif #endif
#else #else
SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM); if (!regs_asm_clobbered[FRAME_POINTER_REGNUM])
if (need_fp) {
SET_HARD_REG_BIT (no_global_alloc_regs, 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);
}
else if (need_fp)
error ("%s cannot be used in asm here", reg_names[FRAME_POINTER_REGNUM]);
#endif #endif
/* Track which registers have already been used. Start with registers /* Track which registers have already been used. Start with registers
......
...@@ -153,11 +153,14 @@ extern bitmap_head subregs_of_mode; ...@@ -153,11 +153,14 @@ extern bitmap_head subregs_of_mode;
extern short *reg_renumber; extern short *reg_renumber;
/* Vector indexed by hardware reg /* Vector indexed by hardware reg saying whether that reg is ever used. */
saying whether that reg is ever used. */
extern char regs_ever_live[FIRST_PSEUDO_REGISTER]; 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. /* 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 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 it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment