diff options
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/basic-block.h | 2 | ||||
-rw-r--r-- | gcc/final.c | 6 | ||||
-rw-r--r-- | gcc/flow.c | 39 | ||||
-rw-r--r-- | gcc/global.c | 40 | ||||
-rw-r--r-- | gcc/regs.h | 7 |
6 files changed, 87 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6ce8f999b23..0cf45b6c3ec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +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> * config/ia64/ia64.h (MUST_PASS_IN_STACK): Define. diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 221b2466985..365711a541d 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -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 --git a/gcc/final.c b/gcc/final.c index 820cb680ab2..53c9359232c 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -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. Initialized in function.c to 0. Set only in reload1.c as per the needs of the function. */ diff --git a/gcc/flow.c b/gcc/flow.c index d131fab5a8b..952e7d9eb92 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -464,7 +464,10 @@ life_analysis (rtx f, FILE *file, int flags) 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. */ @@ -2445,6 +2448,7 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn) 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)) @@ -2453,14 +2457,17 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn) 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: @@ -2483,13 +2490,20 @@ mark_set_regs (struct propagate_block_info *pbi, rtx x, rtx insn) 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: @@ -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++) regs_ever_live[i] = 1; + if (flags & PROP_ASM_SCAN) + for (i = regno_first; i <= regno_last; i++) + regs_asm_clobbered[i] = 1; } else { @@ -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)) 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 --git a/gcc/global.c b/gcc/global.c index c808e207406..c337cd41cfc 100644 --- a/gcc/global.c +++ b/gcc/global.c @@ -343,22 +343,42 @@ global_alloc (FILE *file) #ifdef ELIMINABLE_REGS 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) - || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp)) - SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from); + if (!regs_asm_clobbered[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 - 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); + } + else if (need_fp) + error ("%s cannot be used in asm here", + reg_names[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); + } + else if (need_fp) + error ("%s cannot be used in asm here", reg_names[FRAME_POINTER_REGNUM]); #endif /* Track which registers have already been used. Start with registers diff --git a/gcc/regs.h b/gcc/regs.h index b2aeb5fb02c..9c9edccb26b 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -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 |