diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-09-02 04:20:21 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-09-02 04:20:21 +0000 |
commit | ce71a9e62981c51534492d55d5bf99a08c89853a (patch) | |
tree | 2741b1e654e069ae0926889ad907a3122fc70944 /gcc/reg-stack.c | |
parent | 830a572acbd17d6fb8ae39e7fec9decda08af939 (diff) | |
download | gcc-ce71a9e62981c51534492d55d5bf99a08c89853a.tar.gz |
Merge new ia32 backend from the branch!
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@29044 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/reg-stack.c')
-rw-r--r-- | gcc/reg-stack.c | 802 |
1 files changed, 419 insertions, 383 deletions
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 4da5a7a85dd..d9c40483358 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -160,8 +160,8 @@ Boston, MA 02111-1307, USA. */ #include "hard-reg-set.h" #include "flags.h" #include "insn-flags.h" -#include "recog.h" #include "toplev.h" +#include "recog.h" #include "varray.h" #ifdef STACK_REGS @@ -232,26 +232,13 @@ static rtx /* Get the basic block number of an insn. See note at block_number definition are validity of this information. */ -static int BLOCK_NUM PROTO((rtx)); - -#ifdef __GNUC__ -__inline__ -#endif -static int -BLOCK_NUM(insn) - rtx insn; -{ - int tmp = INSN_UID (insn); - if (tmp > max_uid) - abort (); - tmp = block_number[tmp]; - if (tmp < 0) - abort (); - return tmp; -} +#define BLOCK_NUM(INSN) \ + ((INSN_UID (INSN) > max_uid) \ + ? (abort() , -1) : block_number[INSN_UID (INSN)]) /* Forward declarations */ +static int stack_regs_mentioned_p PROTO((rtx pat)); static void mark_regs_pat PROTO((rtx, HARD_REG_SET *)); static void straighten_stack PROTO((rtx, stack)); static void pop_stack PROTO((stack, int)); @@ -273,7 +260,8 @@ static void delete_insn_for_stacker PROTO((rtx)); static rtx emit_pop_insn PROTO((rtx, stack, rtx, rtx (*) ())); static void emit_swap_insn PROTO((rtx, stack, rtx)); static void move_for_stack_reg PROTO((rtx, stack, rtx)); -static void swap_rtx_condition PROTO((rtx)); +static int swap_rtx_condition_1 PROTO((rtx)); +static int swap_rtx_condition PROTO((rtx)); static void compare_for_stack_reg PROTO((rtx, stack, rtx)); static void subst_stack_regs_pat PROTO((rtx, stack, rtx)); static void subst_asm_stack_regs PROTO((rtx, stack)); @@ -284,47 +272,96 @@ static void goto_block_pat PROTO((rtx, stack, rtx)); static void convert_regs PROTO((void)); static void print_blocks PROTO((FILE *, rtx, rtx)); static void dump_stack_info PROTO((FILE *)); -static int check_stack_regs_mentioned PROTO((rtx insn)); -/* Initialize stack_regs_mentioned_data for INSN (growing the virtual array - if needed. Return nonzero if INSN mentions stacked registers. */ +/* Return non-zero if any stack register is mentioned somewhere within PAT. */ static int -check_stack_regs_mentioned (insn) - rtx insn; +stack_regs_mentioned_p (pat) + rtx pat; { - unsigned int uid = INSN_UID (insn); - if (uid >= VARRAY_SIZE (stack_regs_mentioned_data)) - /* Allocate some extra size to avoid too many reallocs, but - do not grow exponentially. */ - VARRAY_GROW (stack_regs_mentioned_data, uid + uid / 20); - if (stack_regs_mentioned_p (PATTERN (insn))) + register const char *fmt; + register int i; + + if (STACK_REG_P (pat)) + return 1; + + fmt = GET_RTX_FORMAT (GET_CODE (pat)); + for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) { - VARRAY_CHAR (stack_regs_mentioned_data, uid) = 1; - return 1; + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (pat, i) - 1; j >= 0; j--) + if (stack_regs_mentioned_p (XVECEXP (pat, i, j))) + return 1; + } + else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i))) + return 1; } - else - VARRAY_CHAR (stack_regs_mentioned_data, uid) = 2; + return 0; } -/* Return nonzero if INSN mentions stacked registers, else return - zero. */ +/* Return nonzero if INSN mentions stacked registers, else return zero. */ int stack_regs_mentioned (insn) rtx insn; { - unsigned int uid; + unsigned int uid, max; + int test; + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') return 0; + uid = INSN_UID (insn); - if (uid >= VARRAY_SIZE (stack_regs_mentioned_data) - || ! VARRAY_CHAR (stack_regs_mentioned_data, uid)) - return (check_stack_regs_mentioned (insn)); - return VARRAY_CHAR (stack_regs_mentioned_data, uid) == 1; + max = VARRAY_SIZE (stack_regs_mentioned_data); + if (uid >= max) + { + /* Allocate some extra size to avoid too many reallocs, but + do not grow too quickly. */ + max = uid + uid / 20; + VARRAY_GROW (stack_regs_mentioned_data, max); + } + + test = VARRAY_CHAR (stack_regs_mentioned_data, uid); + if (test == 0) + { + /* This insn has yet to be examined. Do so now. */ + test = stack_regs_mentioned_p (PATTERN (insn)) ? 1 : 2; + VARRAY_CHAR (stack_regs_mentioned_data, uid) = test; + } + + return test == 1; } + +static rtx ix86_flags_rtx; +static rtx +next_flags_user (insn) + rtx insn; +{ + /* Search forward looking for the first use of this value. + Stop at block boundaries. */ + /* ??? This really cries for BLOCK_END! */ + + while (1) + { + insn = NEXT_INSN (insn); + if (!insn) + return NULL_RTX; + + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn))) + return insn; + + if (GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CODE_LABEL + || GET_CODE (insn) == CALL_INSN) + return NULL_RTX; + } +} /* Mark all registers needed for this pattern. */ @@ -338,17 +375,17 @@ mark_regs_pat (pat, set) register int count; if (GET_CODE (pat) == SUBREG) - { - mode = GET_MODE (pat); - regno = SUBREG_WORD (pat); - regno += REGNO (SUBREG_REG (pat)); - } + { + mode = GET_MODE (pat); + regno = SUBREG_WORD (pat); + regno += REGNO (SUBREG_REG (pat)); + } else - regno = REGNO (pat), mode = GET_MODE (pat); + regno = REGNO (pat), mode = GET_MODE (pat); for (count = HARD_REGNO_NREGS (regno, mode); count; count--, regno++) - SET_HARD_REG_BIT (*set, regno); + SET_HARD_REG_BIT (*set, regno); } /* Reorganise the stack into ascending numbers, @@ -372,7 +409,7 @@ straighten_stack (insn, regstack) temp_stack.reg_set = regstack->reg_set; for (top = temp_stack.top = regstack->top; top >= 0; top--) - temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top; + temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top; change_stack (insn, regstack, &temp_stack, emit_insn_after); } @@ -403,36 +440,6 @@ pop_stack (regstack, regno) } } -/* Return non-zero if any stack register is mentioned somewhere within PAT. */ - -int -stack_regs_mentioned_p (pat) - rtx pat; -{ - register const char *fmt; - register int i; - - if (STACK_REG_P (pat)) - return 1; - - fmt = GET_RTX_FORMAT (GET_CODE (pat)); - for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) - { - if (fmt[i] == 'E') - { - register int j; - - for (j = XVECLEN (pat, i) - 1; j >= 0; j--) - if (stack_regs_mentioned_p (XVECEXP (pat, i, j))) - return 1; - } - else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i))) - return 1; - } - - return 0; -} - /* Convert register usage from "flat" register file usage to a "stack register file. FIRST is the first insn in the function, FILE is the dump file, if used. @@ -454,15 +461,17 @@ reg_to_stack (first, file) enum machine_mode mode; HARD_REG_SET stackentry; + ix86_flags_rtx = gen_rtx_REG (CCmode, FLAGS_REG); + max_uid = get_max_uid (); VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1, "stack_regs_mentioned cache"); CLEAR_HARD_REG_SET (stackentry); - { - static int initialised; - if (!initialised) + { + static int initialised; + if (!initialised) { #if 0 initialised = 1; /* This array can not have been previously @@ -471,16 +480,16 @@ reg_to_stack (first, file) functions. */ #endif for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++) - { - for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + { + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i); - for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode; - mode = GET_MODE_WIDER_MODE (mode)) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i); - } + } } - } + } /* Count the basic blocks. Also find maximum insn uid. */ { @@ -509,7 +518,7 @@ reg_to_stack (first, file) blocks++; if (code == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) - before_function_beg = 0; + before_function_beg = 0; /* Remember whether or not this insn mentions an FP regs. Check JUMP_INSNs too, in case someone creates a funny PARALLEL. */ @@ -518,7 +527,7 @@ reg_to_stack (first, file) && stack_regs_mentioned_p (PATTERN (insn))) { stack_reg_seen = 1; - VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1; + VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1; /* Note any register passing parameters. */ @@ -565,7 +574,6 @@ reg_to_stack (first, file) bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET)); block_number = (int *) alloca ((max_uid + 1) * sizeof (int)); - memset (block_number, -1, (max_uid + 1) * sizeof (int)); find_blocks (first); stack_reg_life_analysis (first, &stackentry); @@ -648,32 +656,30 @@ get_true_reg (pat) rtx *pat; { for (;;) - switch (GET_CODE (*pat)) + switch (GET_CODE (*pat)) { - case SUBREG: - /* eliminate FP subregister accesses in favour of the - actual FP register in use. */ - { - rtx subreg; - if (FP_REG_P (subreg = SUBREG_REG (*pat))) + case SUBREG: + /* Eliminate FP subregister accesses in favour of the + actual FP register in use. */ + { + rtx subreg; + if (FP_REG_P (subreg = SUBREG_REG (*pat))) { *pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat), GET_MODE (subreg)); - default: + default: return pat; } - } - case FLOAT: - case FIX: - case FLOAT_EXTEND: - pat = & XEXP (*pat, 0); + } + case FLOAT: + case FIX: + case FLOAT_EXTEND: + pat = & XEXP (*pat, 0); } } /* Record the life info of each stack reg in INSN, updating REGSTACK. N_INPUTS is the number of inputs; N_OUTPUTS the outputs. - OPERANDS is an array of all operands for the insn, and is assumed to - contain all output operands, then all inputs operands. There are many rules that an asm statement for stack-like regs must follow. Those rules are explained at the top of this file: the rule @@ -712,7 +718,7 @@ record_asm_reg_life (insn, regstack) malformed_asm = 1; /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx); - VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2; + PUT_MODE (insn, VOIDmode); return; } @@ -917,10 +923,10 @@ record_reg_life_pat (pat, src, dest, douse) || (GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat)))) { if (src) - mark_regs_pat (pat, src); + mark_regs_pat (pat, src); if (dest) - mark_regs_pat (pat, dest); + mark_regs_pat (pat, dest); return; } @@ -1022,74 +1028,74 @@ record_reg_life (insn, block, regstack) return; } - { - HARD_REG_SET src, dest; - int regno; - - CLEAR_HARD_REG_SET (src); - CLEAR_HARD_REG_SET (dest); - - if (GET_CODE (insn) == CALL_INSN) - for (note = CALL_INSN_FUNCTION_USAGE (insn); - note; - note = XEXP (note, 1)) - if (GET_CODE (XEXP (note, 0)) == USE) - record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0); - - record_reg_life_pat (PATTERN (insn), &src, &dest, 0); - for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++) - if (! TEST_HARD_REG_BIT (regstack->reg_set, regno)) - { - if (TEST_HARD_REG_BIT (src, regno) - && ! TEST_HARD_REG_BIT (dest, regno)) - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, - FP_MODE_REG (regno, DFmode), - REG_NOTES (insn)); - else if (TEST_HARD_REG_BIT (dest, regno)) - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED, - FP_MODE_REG (regno, DFmode), - REG_NOTES (insn)); - } + { + HARD_REG_SET src, dest; + int regno; + + CLEAR_HARD_REG_SET (src); + CLEAR_HARD_REG_SET (dest); + + if (GET_CODE (insn) == CALL_INSN) + for (note = CALL_INSN_FUNCTION_USAGE (insn); + note; + note = XEXP (note, 1)) + if (GET_CODE (XEXP (note, 0)) == USE) + record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0); + + record_reg_life_pat (PATTERN (insn), &src, &dest, 0); + for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++) + if (! TEST_HARD_REG_BIT (regstack->reg_set, regno)) + { + if (TEST_HARD_REG_BIT (src, regno) + && ! TEST_HARD_REG_BIT (dest, regno)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, + FP_MODE_REG (regno, DFmode), + REG_NOTES (insn)); + else if (TEST_HARD_REG_BIT (dest, regno)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED, + FP_MODE_REG (regno, DFmode), + REG_NOTES (insn)); + } - if (GET_CODE (insn) == CALL_INSN) - { - int reg; + if (GET_CODE (insn) == CALL_INSN) + { + int reg; - /* There might be a reg that is live after a function call. - Initialize it to zero so that the program does not crash. See - comment towards the end of stack_reg_life_analysis(). */ + /* There might be a reg that is live after a function call. + Initialize it to zero so that the program does not crash. See + comment towards the end of stack_reg_life_analysis(). */ - for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++) - if (! TEST_HARD_REG_BIT (dest, reg) - && TEST_HARD_REG_BIT (regstack->reg_set, reg)) - { - rtx init, pat; + for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++) + if (! TEST_HARD_REG_BIT (dest, reg) + && TEST_HARD_REG_BIT (regstack->reg_set, reg)) + { + rtx init, pat; - /* The insn will use virtual register numbers, and so - convert_regs is expected to process these. But BLOCK_NUM - cannot be used on these insns, because they do not appear in - block_number[]. */ + /* The insn will use virtual register numbers, and so + convert_regs is expected to process these. But BLOCK_NUM + cannot be used on these insns, because they do not appear in + block_number[]. */ - pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode), - CONST0_RTX (DFmode)); - init = emit_insn_after (pat, insn); + pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode), + CONST0_RTX (DFmode)); + init = emit_insn_after (pat, insn); - CLEAR_HARD_REG_BIT (regstack->reg_set, reg); + CLEAR_HARD_REG_BIT (regstack->reg_set, reg); - /* If the CALL_INSN was the end of a block, move the - block_end to point to the new insn. */ + /* If the CALL_INSN was the end of a block, move the + block_end to point to the new insn. */ - if (block_end[block] == insn) - block_end[block] = init; - } + if (block_end[block] == insn) + block_end[block] = init; + } - /* Some regs do not survive a CALL */ - AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set); - } + /* Some regs do not survive a CALL */ + AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set); + } - AND_COMPL_HARD_REG_SET (regstack->reg_set, dest); - IOR_HARD_REG_SET (regstack->reg_set, src); - } + AND_COMPL_HARD_REG_SET (regstack->reg_set, dest); + IOR_HARD_REG_SET (regstack->reg_set, src); + } } /* Find all basic blocks of the function, which starts with FIRST. @@ -1240,26 +1246,26 @@ stack_reg_life_analysis (first, stackentry) int reg, block; struct stack_def regstack; - { - rtx retvalue; + { + rtx retvalue; - if ((retvalue = stack_result (current_function_decl))) + if ((retvalue = stack_result (current_function_decl))) { /* Find all RETURN insns and mark them. */ for (block = blocks - 1; --block >= 0;) - if (GET_CODE (block_end[block]) == JUMP_INSN - && returnjump_p (block_end[block])) - mark_regs_pat (retvalue, block_out_reg_set+block); + if (GET_CODE (block_end[block]) == JUMP_INSN + && returnjump_p (block_end[block])) + mark_regs_pat (retvalue, block_out_reg_set+block); /* Mark off the end of last block if we "fall off" the end of the function into the epilogue. */ if (GET_CODE (block_end[blocks-1]) != JUMP_INSN - || returnjump_p (block_end[blocks-1])) + || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN) mark_regs_pat (retvalue, block_out_reg_set+blocks-1); } - } + } /* now scan all blocks backward for stack register use */ @@ -1343,10 +1349,10 @@ stack_reg_life_analysis (first, stackentry) block -= 1; } - /* If any reg is live at the start of the first block of a - function, then we must guarantee that the reg holds some value by - generating our own "load" of that register. Otherwise a 387 would - fault trying to access an empty register. */ + /* If any reg is live at the start of the first block of a + function, then we must guarantee that the reg holds some value by + generating our own "load" of that register. Otherwise a 387 would + fault trying to access an empty register. */ /* Load zero into each live register. The fact that a register appears live at the function start necessarily implies an error @@ -1373,10 +1379,10 @@ stack_reg_life_analysis (first, stackentry) } } -/***************************************************************************** - This section deals with stack register substitution, and forms the second - pass over the RTL. - *****************************************************************************/ +/* + * This section deals with stack register substitution, and forms the second + * pass over the RTL. + */ /* Replace REG, which is a pointer to a stack reg RTX, with an RTX for the desired hard REGNO. */ @@ -1391,11 +1397,11 @@ replace_reg (reg, regno) abort (); switch (GET_MODE_CLASS (GET_MODE (*reg))) - { - default: abort (); - case MODE_FLOAT: - case MODE_COMPLEX_FLOAT:; - } + { + default: abort (); + case MODE_FLOAT: + case MODE_COMPLEX_FLOAT:; + } *reg = FP_MODE_REG (regno, GET_MODE (*reg)); } @@ -1454,14 +1460,6 @@ static void delete_insn_for_stacker (insn) rtx insn; { - int i; - - /* Ensure that the side effects were clobbers when deleting a PARALLEL. */ - if (GET_CODE (PATTERN (insn)) == PARALLEL) - for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++) - if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) != CLOBBER) - abort (); - PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; @@ -1469,12 +1467,9 @@ delete_insn_for_stacker (insn) /* Emit an insn to pop virtual register REG before or after INSN. REGSTACK is the stack state after INSN and is updated to reflect this - pop. WHEN is either emit_insn_before, emit_insn_after or NULL. - in case WHEN is NULL we don't really emit the insn, just modify stack - information. Caller is expected to emit insn himself. - - A pop insn is represented as a SET whose destination is the register to - be popped and source is the top of stack. A death note for the top of stack + pop. WHEN is either emit_insn_before or emit_insn_after. A pop insn + is represented as a SET whose destination is the register to be popped + and source is the top of stack. A death note for the top of stack cases the movdf pattern to pop. */ static rtx @@ -1492,18 +1487,14 @@ emit_pop_insn (insn, regstack, reg, when) if (hard_regno < FIRST_STACK_REG) abort (); - if (when) - { - pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode), - FP_MODE_REG (FIRST_STACK_REG, DFmode)); + pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode), + FP_MODE_REG (FIRST_STACK_REG, DFmode)); - pop_insn = (*when) (pop_rtx, insn); + pop_insn = (*when) (pop_rtx, insn); - REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD, - FP_MODE_REG (FIRST_STACK_REG, - DFmode), - REG_NOTES (pop_insn)); - } + REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD, + FP_MODE_REG (FIRST_STACK_REG, DFmode), + REG_NOTES (pop_insn)); regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)] = regstack->reg[regstack->top]; @@ -1528,7 +1519,6 @@ emit_swap_insn (insn, regstack, reg) rtx reg; { int hard_regno; - rtx gen_swapdf(); rtx swap_rtx, swap_insn; int tmp, other_reg; /* swap regno temps */ rtx i1; /* the stack-reg insn prior to INSN */ @@ -1578,15 +1568,8 @@ emit_swap_insn (insn, regstack, reg) return; } - if (GET_RTX_CLASS (GET_CODE (i1)) == 'i' && sets_cc0_p (PATTERN (i1))) - { - i1 = next_nonnote_insn (i1); - if (i1 == insn) - abort (); - } - - swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode), - FP_MODE_REG (FIRST_STACK_REG, DFmode)); + swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode), + FP_MODE_REG (FIRST_STACK_REG, XFmode)); swap_insn = emit_insn_after (swap_rtx, i1); } @@ -1732,109 +1715,144 @@ move_for_stack_reg (insn, regstack, pat) abort (); } -static void -swap_rtx_condition (pat) +/* Swap the condition on a branch, if there is one. Return true if we + found a condition to swap. False if the condition was not used as + such. */ + +static int +swap_rtx_condition_1 (pat) rtx pat; { register const char *fmt; - register int i; + register int i, r = 0; if (GET_RTX_CLASS (GET_CODE (pat)) == '<') { PUT_CODE (pat, swap_condition (GET_CODE (pat))); - return; + r = 1; } - - fmt = GET_RTX_FORMAT (GET_CODE (pat)); - for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) + else { - if (fmt[i] == 'E') + fmt = GET_RTX_FORMAT (GET_CODE (pat)); + for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) { - register int j; + if (fmt[i] == 'E') + { + register int j; - for (j = XVECLEN (pat, i) - 1; j >= 0; j--) - swap_rtx_condition (XVECEXP (pat, i, j)); + for (j = XVECLEN (pat, i) - 1; j >= 0; j--) + r |= swap_rtx_condition_1 (XVECEXP (pat, i, j)); + } + else if (fmt[i] == 'e') + r |= swap_rtx_condition_1 (XEXP (pat, i)); } - else if (fmt[i] == 'e') - swap_rtx_condition (XEXP (pat, i)); } + + return r; +} + +static int +swap_rtx_condition (insn) + rtx insn; +{ + rtx pat = PATTERN (insn); + + /* We're looking for a single set to cc0 or an HImode temporary. */ + + if (GET_CODE (pat) == SET + && GET_CODE (SET_DEST (pat)) == REG + && REGNO (SET_DEST (pat)) == FLAGS_REG) + { + insn = next_flags_user (insn); + if (insn == NULL_RTX) + return 0; + pat = PATTERN (insn); + } + + /* See if this is, or ends in, a fnstsw, aka unspec 9. If so, we're + not doing anything with the cc value right now. We may be able to + search for one though. */ + + if (GET_CODE (pat) == SET + && GET_CODE (SET_SRC (pat)) == UNSPEC + && XINT (SET_SRC (pat), 1) == 9) + { + rtx dest = SET_DEST (pat); + + /* Search forward looking for the first use of this value. + Stop at block boundaries. */ + /* ??? This really cries for BLOCK_END! */ + while (1) + { + insn = NEXT_INSN (insn); + if (insn == NULL_RTX) + return 0; + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' + && reg_mentioned_p (dest, insn)) + break; + if (GET_CODE (insn) == JUMP_INSN) + return 0; + if (GET_CODE (insn) == CODE_LABEL) + return 0; + } + + /* So we've found the insn using this value. If it is anything + other than sahf, aka unspec 10, or the value does not die + (meaning we'd have to search further), then we must give up. */ + pat = PATTERN (insn); + if (GET_CODE (pat) != SET + || GET_CODE (SET_SRC (pat)) != UNSPEC + || XINT (SET_SRC (pat), 1) != 10 + || ! dead_or_set_p (insn, dest)) + return 0; + + /* Now we are prepared to handle this as a normal cc0 setter. */ + insn = next_flags_user (insn); + if (insn == NULL_RTX) + return 0; + pat = PATTERN (insn); + } + + return swap_rtx_condition_1 (pat); } /* Handle a comparison. Special care needs to be taken to avoid causing comparisons that a 387 cannot do correctly, such as EQ. - Also, a fstp instruction may need to be emitted. The 387 does have an + Also, a pop insn may need to be emitted. The 387 does have an `fcompp' insn that can pop two regs, but it is sometimes too expensive to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to - set up. - - We can not handle this by emiting fpop instruction after compare, because - it appears between cc0 setter and user. So we emit only - REG_DEAD note and handle it as a special case in machine description. - - This code used trick with delay_slot filling to emit pop insn after - comparsion but it didn't worked because it caused confusion with cc_status - in final pass. */ + set up. */ static void -compare_for_stack_reg (insn, regstack, pat) +compare_for_stack_reg (insn, regstack, pat_src) rtx insn; stack regstack; - rtx pat; + rtx pat_src; { rtx *src1, *src2; rtx src1_note, src2_note; - rtx cc0_user; - int have_cmove; - int hard_regno; + rtx flags_user; - src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); - src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); - cc0_user = next_cc0_user (insn); - - /* If the insn that uses cc0 is an FP-conditional move, then the destination - must be the top of stack */ - if (GET_CODE (PATTERN (cc0_user)) == SET - && SET_DEST (PATTERN (cc0_user)) != pc_rtx - && GET_CODE (SET_SRC (PATTERN (cc0_user))) == IF_THEN_ELSE - && (GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (cc0_user)))) - == MODE_FLOAT)) - { - rtx *dest; - - dest = get_true_reg (&SET_DEST (PATTERN (cc0_user))); - - have_cmove = 1; - if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG - && REGNO (*dest) != regstack->reg[regstack->top]) - { - emit_swap_insn (insn, regstack, *dest); - } - } - else - have_cmove = 0; + src1 = get_true_reg (&XEXP (pat_src, 0)); + src2 = get_true_reg (&XEXP (pat_src, 1)); + flags_user = next_flags_user (insn); /* ??? If fxch turns out to be cheaper than fstp, give priority to registers that die in this insn - move those to stack top first. */ - if (! STACK_REG_P (*src1) - || (STACK_REG_P (*src2) - && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG)) + if ((! STACK_REG_P (*src1) + || (STACK_REG_P (*src2) + && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG)) + && swap_rtx_condition (insn)) { - rtx temp, next; - - temp = XEXP (SET_SRC (pat), 0); - XEXP (SET_SRC (pat), 0) = XEXP (SET_SRC (pat), 1); - XEXP (SET_SRC (pat), 1) = temp; + rtx temp; + temp = XEXP (pat_src, 0); + XEXP (pat_src, 0) = XEXP (pat_src, 1); + XEXP (pat_src, 1) = temp; - src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); - src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); - - next = next_cc0_user (insn); - if (next == NULL_RTX) - abort (); + src1 = get_true_reg (&XEXP (pat_src, 0)); + src2 = get_true_reg (&XEXP (pat_src, 1)); - swap_rtx_condition (PATTERN (next)); - INSN_CODE (next) = -1; INSN_CODE (insn) = -1; } @@ -1847,16 +1865,12 @@ compare_for_stack_reg (insn, regstack, pat) else src2_note = NULL_RTX; - if (! have_cmove) - emit_swap_insn (insn, regstack, *src1); + emit_swap_insn (insn, regstack, *src1); replace_reg (src1, FIRST_STACK_REG); if (STACK_REG_P (*src2)) - { - hard_regno = get_hard_regnum (regstack, *src2); - replace_reg (src2, hard_regno); - } + replace_reg (src2, get_hard_regnum (regstack, *src2)); if (src1_note) { @@ -1885,11 +1899,16 @@ compare_for_stack_reg (insn, regstack, pat) } else { - /* Pop of second operand is handled using special REG_DEAD note - because we can't emit pop insn after cc0 setter. */ + /* The 386 can only represent death of the first operand in + the case handled above. In all other cases, emit a separate + pop and remove the death note from here. */ + + /* link_cc0_insns (insn); */ - emit_pop_insn (insn, regstack, XEXP (src2_note, 0), NULL); - replace_reg (&XEXP (src2_note, 0), hard_regno); + remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0))); + + emit_pop_insn (insn, regstack, XEXP (src2_note, 0), + emit_insn_after); } } } @@ -1906,12 +1925,14 @@ subst_stack_regs_pat (insn, regstack, pat) rtx *dest, *src; rtx *src1 = (rtx *) NULL_PTR, *src2; rtx src1_note, src2_note; + rtx pat_src; if (GET_CODE (pat) != SET) return; dest = get_true_reg (&SET_DEST (pat)); src = get_true_reg (&SET_SRC (pat)); + pat_src = SET_SRC (pat); /* See if this is a `movM' pattern, and handle elsewhere if so. */ @@ -1922,22 +1943,22 @@ subst_stack_regs_pat (insn, regstack, pat) || GET_CODE (*src) == CONST_DOUBLE)))) move_for_stack_reg (insn, regstack, pat); else - switch (GET_CODE (SET_SRC (pat))) + switch (GET_CODE (pat_src)) { case COMPARE: - compare_for_stack_reg (insn, regstack, pat); + compare_for_stack_reg (insn, regstack, pat_src); break; case CALL: - { - int count; - for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest)); - --count >= 0;) + { + int count; + for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest)); + --count >= 0;) { regstack->reg[++regstack->top] = REGNO (*dest) + count; SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count); } - } + } replace_reg (dest, FIRST_STACK_REG); break; @@ -1960,7 +1981,7 @@ subst_stack_regs_pat (insn, regstack, pat) source. */ if (src1 == 0) - src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); + src1 = get_true_reg (&XEXP (pat_src, 0)); emit_swap_insn (insn, regstack, *src1); @@ -1992,8 +2013,8 @@ subst_stack_regs_pat (insn, regstack, pat) source and some other stack register (possibly top of stack) as a destination. */ - src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); - src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); + src1 = get_true_reg (&XEXP (pat_src, 0)); + src2 = get_true_reg (&XEXP (pat_src, 1)); /* We will fix any death note later. */ @@ -2095,13 +2116,13 @@ subst_stack_regs_pat (insn, regstack, pat) break; case UNSPEC: - switch (XINT (SET_SRC (pat), 1)) + switch (XINT (pat_src, 1)) { case 1: /* sin */ case 2: /* cos */ /* These insns only operate on the top of the stack. */ - src1 = get_true_reg (&XVECEXP (SET_SRC (pat), 0, 0)); + src1 = get_true_reg (&XVECEXP (pat_src, 0, 0)); emit_swap_insn (insn, regstack, *src1); @@ -2121,16 +2142,35 @@ subst_stack_regs_pat (insn, regstack, pat) break; + case 10: + /* (unspec [(unspec [(compare ..)] 9)] 10) + Unspec 9 is fnstsw; unspec 10 is sahf. The combination + matches the PPRO fcomi instruction. */ + + pat_src = XVECEXP (pat_src, 0, 0); + if (GET_CODE (pat_src) != UNSPEC + || XINT (pat_src, 1) != 9) + abort (); + /* FALLTHRU */ + + case 9: + /* (unspec [(compare ..)] 9) + Combined fcomp+fnstsw generated for doing well with CSE. + When optimizing this would have been broken up before now. */ + + pat_src = XVECEXP (pat_src, 0, 0); + if (GET_CODE (pat_src) != COMPARE) + abort (); + + compare_for_stack_reg (insn, regstack, pat_src); + break; + default: abort (); } break; case IF_THEN_ELSE: - /* dest has to be on stack. */ - if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG) - abort (); - /* This insn requires the top of stack to be the destination. */ /* If the comparison operator is an FP comparison operator, @@ -2142,8 +2182,8 @@ subst_stack_regs_pat (insn, regstack, pat) && REGNO (*dest) != regstack->reg[regstack->top]) emit_swap_insn (insn, regstack, *dest); - src1 = get_true_reg (&XEXP (SET_SRC (pat), 1)); - src2 = get_true_reg (&XEXP (SET_SRC (pat), 2)); + src1 = get_true_reg (&XEXP (pat_src, 1)); + src2 = get_true_reg (&XEXP (pat_src, 2)); src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2)); @@ -2184,7 +2224,9 @@ subst_stack_regs_pat (insn, regstack, pat) } } - /* Make dest the top of stack. */ + /* Make dest the top of stack. Add dest to regstack if not present. */ + if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG) + regstack->reg[++regstack->top] = REGNO (*dest); SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); replace_reg (dest, FIRST_STACK_REG); @@ -2500,26 +2542,26 @@ subst_stack_regs (insn, regstack) register int i; if (GET_CODE (insn) == CALL_INSN) - { - int top = regstack->top; + { + int top = regstack->top; - /* If there are any floating point parameters to be passed in - registers for this call, make sure they are in the right - order. */ + /* If there are any floating point parameters to be passed in + registers for this call, make sure they are in the right + order. */ - if (top >= 0) - { - straighten_stack (PREV_INSN (insn), regstack); + if (top >= 0) + { + straighten_stack (PREV_INSN (insn), regstack); - /* Now mark the arguments as dead after the call. */ + /* Now mark the arguments as dead after the call. */ - while (regstack->top >= 0) - { - CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top); - regstack->top--; - } - } - } + while (regstack->top >= 0) + { + CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top); + regstack->top--; + } + } + } /* Do the actual substitution if any stack regs are mentioned. Since we only record whether entire insn mentions stack regs, and @@ -2544,14 +2586,8 @@ subst_stack_regs (insn, regstack) for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) { if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i))) - { - subst_stack_regs_pat (insn, regstack, - XVECEXP (PATTERN (insn), 0, i)); - - /* subst_stack_regs_pat may have deleted a no-op insn. */ - if (GET_CODE (insn) == NOTE) - break; - } + subst_stack_regs_pat (insn, regstack, + XVECEXP (PATTERN (insn), 0, i)); } else subst_stack_regs_pat (insn, regstack, PATTERN (insn)); @@ -2712,27 +2748,27 @@ goto_block_pat (insn, regstack, pat) int reg; switch (GET_CODE (pat)) - { - case RETURN: - straighten_stack (PREV_INSN (insn), regstack); - return; - default: - { - int i, j; - const char *fmt = GET_RTX_FORMAT (GET_CODE (pat)); - - for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - goto_block_pat (insn, regstack, XEXP (pat, i)); - if (fmt[i] == 'E') - for (j = 0; j < XVECLEN (pat, i); j++) - goto_block_pat (insn, regstack, XVECEXP (pat, i, j)); - } + { + case RETURN: + straighten_stack (PREV_INSN (insn), regstack); return; - } - case LABEL_REF:; - } + default: + { + int i, j; + const char *fmt = GET_RTX_FORMAT (GET_CODE (pat)); + + for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + goto_block_pat (insn, regstack, XEXP (pat, i)); + if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (pat, i); j++) + goto_block_pat (insn, regstack, XVECEXP (pat, i, j)); + } + return; + } + case LABEL_REF:; + } label = XEXP (pat, 0); if (GET_CODE (label) != CODE_LABEL) @@ -2896,26 +2932,26 @@ convert_regs () regs live at its start, then the last basic block will have regs live at its end that need to be popped before the function returns. */ - { - int value_reg_low, value_reg_high; - value_reg_low = value_reg_high = -1; - { - rtx retvalue; - if ((retvalue = stack_result (current_function_decl))) - { - value_reg_low = REGNO (retvalue); - value_reg_high = value_reg_low + + { + int value_reg_low, value_reg_high; + value_reg_low = value_reg_high = -1; + { + rtx retvalue; + if ((retvalue = stack_result (current_function_decl))) + { + value_reg_low = REGNO (retvalue); + value_reg_high = value_reg_low + HARD_REGNO_NREGS (value_reg_low, GET_MODE (retvalue)) - 1; - } + } - } - for (reg = regstack.top; reg >= 0; reg--) - if (regstack.reg[reg] < value_reg_low - || regstack.reg[reg] > value_reg_high) - insn = emit_pop_insn (insn, ®stack, - FP_MODE_REG (regstack.reg[reg], DFmode), - emit_insn_after); - } + } + for (reg = regstack.top; reg >= 0; reg--) + if (regstack.reg[reg] < value_reg_low + || regstack.reg[reg] > value_reg_high) + insn = emit_pop_insn (insn, ®stack, + FP_MODE_REG (regstack.reg[reg], DFmode), + emit_insn_after); + } straighten_stack (insn, ®stack); } |