diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b29c3f3cd77..9238255e2ff 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2004-01-28 Zack Weinberg + Jim Wilson + + * config/ia64/ia64.c (ia64_split_tmode, ia64_split_tmode_move): + Rewrite to use POST_INC/POST_DEC/POST_MODIFY instead of a + scratch pointer. + (ia64_secondary_reload_class): Delete case GR_REGS. + * config/ia64/ia64.md (movti, *movti_internal, movtf, *movtf_internal): + Do not allocate a scratch register. + (reload_inti, reload_outti, reload_intf, reload_outtf): Delete. + 2004-01-28 Jan Hubicka * gcse.c (bypass_block): Prevent edges to be unified when we are @@ -43,7 +54,7 @@ * config/s390/s390.h (TARGET_DEFAULT): Default to !TARGET_BACKCHAIN. * config/s390/s390.c (s390_return_addr_rtx): Fail for all but current frame if !TARGET_BACKCHAIN. - * config/s390/s390.md ("allocate_stack"): Use pattern only if + * config/s390/s390.md ("allocate_stack"): Use pattern only if TARGET_BACKCHAIN. * doc/invoke.texi (-mbackchain/-mno-backchain): Document new default. diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 5271081b3e9..12b563faadb 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -1395,62 +1395,37 @@ ia64_emit_cond_move (rtx op0, rtx op1, rtx cond) } /* Split a post-reload TImode or TFmode reference into two DImode - components. */ + components. This is made extra difficult by the fact that we do + not get any scratch registers to work with, because reload cannot + be prevented from giving us a scratch that overlaps the register + pair involved. So instead, when addressing memory, we tweak the + pointer register up and back down with POST_INCs. Or up and not + back down when we can get away with it. + + REVERSED is true when the loads must be done in reversed order + (high word first) for correctness. DEAD is true when the pointer + dies with the second insn we generate and therefore the second + address must not carry a postmodify. + + May return an insn which is to be emitted after the moves. */ static rtx -ia64_split_tmode (rtx out[2], rtx in, rtx scratch) +ia64_split_tmode (rtx out[2], rtx in, bool reversed, bool dead) { + rtx fixup = 0; + switch (GET_CODE (in)) { case REG: - out[0] = gen_rtx_REG (DImode, REGNO (in)); - out[1] = gen_rtx_REG (DImode, REGNO (in) + 1); - return NULL_RTX; - - case MEM: - { - rtx base = XEXP (in, 0); - - switch (GET_CODE (base)) - { - case REG: - out[0] = adjust_address (in, DImode, 0); - break; - case POST_MODIFY: - base = XEXP (base, 0); - out[0] = adjust_address (in, DImode, 0); - break; - - /* Since we're changing the mode, we need to change to POST_MODIFY - as well to preserve the size of the increment. Either that or - do the update in two steps, but we've already got this scratch - register handy so let's use it. */ - case POST_INC: - base = XEXP (base, 0); - out[0] - = change_address (in, DImode, - gen_rtx_POST_MODIFY - (Pmode, base, plus_constant (base, 16))); - break; - case POST_DEC: - base = XEXP (base, 0); - out[0] - = change_address (in, DImode, - gen_rtx_POST_MODIFY - (Pmode, base, plus_constant (base, -16))); - break; - default: - abort (); - } - - if (scratch == NULL_RTX) - abort (); - out[1] = change_address (in, DImode, scratch); - return gen_adddi3 (scratch, base, GEN_INT (8)); - } + out[reversed] = gen_rtx_REG (DImode, REGNO (in)); + out[!reversed] = gen_rtx_REG (DImode, REGNO (in) + 1); + break; case CONST_INT: case CONST_DOUBLE: + /* Cannot occur reversed. */ + if (reversed) abort (); + if (GET_MODE (in) != TFmode) split_double (in, &out[0], &out[1]); else @@ -1477,11 +1452,108 @@ ia64_split_tmode (rtx out[2], rtx in, rtx scratch) out[0] = GEN_INT (p[0]); out[1] = GEN_INT (p[1]); } - return NULL_RTX; + break; + + case MEM: + { + rtx base = XEXP (in, 0); + rtx offset; + + switch (GET_CODE (base)) + { + case REG: + if (!reversed) + { + out[0] = adjust_automodify_address + (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); + out[1] = adjust_automodify_address + (in, DImode, dead ? 0 : gen_rtx_POST_DEC (Pmode, base), 8); + } + else + { + /* Reversal requires a pre-increment, which can only + be done as a separate insn. */ + emit_insn (gen_adddi3 (base, base, GEN_INT (8))); + out[0] = adjust_automodify_address + (in, DImode, gen_rtx_POST_DEC (Pmode, base), 8); + out[1] = adjust_address (in, DImode, 0); + } + break; + + case POST_INC: + if (reversed || dead) abort (); + /* Just do the increment in two steps. */ + out[0] = adjust_automodify_address (in, DImode, 0, 0); + out[1] = adjust_automodify_address (in, DImode, 0, 8); + break; + + case POST_DEC: + if (reversed || dead) abort (); + /* Add 8, subtract 24. */ + base = XEXP (base, 0); + out[0] = adjust_automodify_address + (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); + out[1] = adjust_automodify_address + (in, DImode, + gen_rtx_POST_MODIFY (Pmode, base, plus_constant (base, -24)), + 8); + break; + + case POST_MODIFY: + if (reversed || dead) abort (); + /* Extract and adjust the modification. This case is + trickier than the others, because we might have an + index register, or we might have a combined offset that + doesn't fit a signed 9-bit displacement field. We can + assume the incoming expression is already legitimate. */ + offset = XEXP (base, 1); + base = XEXP (base, 0); + + out[0] = adjust_automodify_address + (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); + + if (GET_CODE (XEXP (offset, 1)) == REG) + { + /* Can't adjust the postmodify to match. Emit the + original, then a separate addition insn. */ + out[1] = adjust_automodify_address (in, DImode, 0, 8); + fixup = gen_adddi3 (base, base, GEN_INT (-8)); + } + else if (GET_CODE (XEXP (offset, 1)) != CONST_INT) + abort (); + else if (INTVAL (XEXP (offset, 1)) < -256 + 8) + { + /* Again the postmodify cannot be made to match, but + in this case it's more efficient to get rid of the + postmodify entirely and fix up with an add insn. */ + out[1] = adjust_automodify_address (in, DImode, base, 8); + fixup = gen_adddi3 (base, base, + GEN_INT (INTVAL (XEXP (offset, 1)) - 8)); + } + else + { + /* Combined offset still fits in the displacement field. + (We cannot overflow it at the high end.) */ + out[1] = adjust_automodify_address + (in, DImode, + gen_rtx_POST_MODIFY (Pmode, base, + gen_rtx_PLUS (Pmode, base, + GEN_INT (INTVAL (XEXP (offset, 1)) - 8))), + 8); + } + break; + + default: + abort (); + } + break; + } default: abort (); } + + return fixup; } /* Split a TImode or TFmode move instruction after reload. @@ -1489,39 +1561,60 @@ ia64_split_tmode (rtx out[2], rtx in, rtx scratch) void ia64_split_tmode_move (rtx operands[]) { - rtx adj1, adj2, in[2], out[2], insn; - int first; + rtx in[2], out[2], insn; + rtx fixup[2]; + bool dead = false; + bool reversed = false; - adj1 = ia64_split_tmode (in, operands[1], operands[2]); - adj2 = ia64_split_tmode (out, operands[0], operands[2]); - - first = 0; - if (reg_overlap_mentioned_p (out[0], in[1])) + /* It is possible for reload to decide to overwrite a pointer with + the value it points to. In that case we have to do the loads in + the appropriate order so that the pointer is not destroyed too + early. Also we must not generate a postmodify for that second + load, or rws_access_regno will abort. */ + if (GET_CODE (operands[1]) == MEM + && reg_overlap_mentioned_p (operands[0], operands[1])) { - if (reg_overlap_mentioned_p (out[1], in[0])) - abort (); - first = 1; + rtx base = XEXP (operands[1], 0); + while (GET_CODE (base) != REG) + base = XEXP (base, 0); + + if (REGNO (base) == REGNO (operands[0])) + reversed = true; + dead = true; } + /* Another reason to do the moves in reversed order is if the first + element of the target register pair is also the second element of + the source register pair. */ + if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG + && REGNO (operands[0]) == REGNO (operands[1]) + 1) + reversed = true; - if (adj1 && adj2) - abort (); - if (adj1) - emit_insn (adj1); - if (adj2) - emit_insn (adj2); - insn = emit_insn (gen_rtx_SET (VOIDmode, out[first], in[first])); - if (GET_CODE (out[first]) == MEM - && GET_CODE (XEXP (out[first], 0)) == POST_MODIFY) - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, - XEXP (XEXP (out[first], 0), 0), - REG_NOTES (insn)); - insn = emit_insn (gen_rtx_SET (VOIDmode, out[!first], in[!first])); - if (GET_CODE (out[!first]) == MEM - && GET_CODE (XEXP (out[!first], 0)) == POST_MODIFY) - REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, - XEXP (XEXP (out[!first], 0), 0), - REG_NOTES (insn)); + fixup[0] = ia64_split_tmode (in, operands[1], reversed, dead); + fixup[1] = ia64_split_tmode (out, operands[0], reversed, dead); +#define MAYBE_ADD_REG_INC_NOTE(INSN, EXP) \ + if (GET_CODE (EXP) == MEM \ + && (GET_CODE (XEXP (EXP, 0)) == POST_MODIFY \ + || GET_CODE (XEXP (EXP, 0)) == POST_INC \ + || GET_CODE (XEXP (EXP, 0)) == POST_DEC)) \ + REG_NOTES (INSN) = gen_rtx_EXPR_LIST (REG_INC, \ + XEXP (XEXP (EXP, 0), 0), \ + REG_NOTES (INSN)) + + insn = emit_insn (gen_rtx_SET (VOIDmode, out[0], in[0])); + MAYBE_ADD_REG_INC_NOTE (insn, in[0]); + MAYBE_ADD_REG_INC_NOTE (insn, out[0]); + + insn = emit_insn (gen_rtx_SET (VOIDmode, out[1], in[1])); + MAYBE_ADD_REG_INC_NOTE (insn, in[1]); + MAYBE_ADD_REG_INC_NOTE (insn, out[1]); + + if (fixup[0]) + emit_insn (fixup[0]); + if (fixup[1]) + emit_insn (fixup[1]); + +#undef MAYBE_ADD_REG_INC_NOTE } /* ??? Fixing GR->FR XFmode moves during reload is hard. You need to go @@ -4492,13 +4585,6 @@ ia64_secondary_reload_class (enum reg_class class, return GR_REGS; break; - case GR_REGS: - /* Since we have no offsettable memory addresses, we need a temporary - to hold the address of the second word. */ - if (mode == TImode || mode == TFmode) - return GR_REGS; - break; - default: break; } diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md index 635100c4281..2713eb624aa 100644 --- a/gcc/config/ia64/ia64.md +++ b/gcc/config/ia64/ia64.md @@ -584,11 +584,12 @@ [(set_attr "itanium_class" "ialu")]) ;; With no offsettable memory references, we've got to have a scratch -;; around to play with the second word. +;; around to play with the second word. However, in order to avoid a +;; reload nightmare we lie, claim we don't need one, and fix it up +;; in ia64_split_tmode_move. (define_expand "movti" - [(parallel [(set (match_operand:TI 0 "general_operand" "") - (match_operand:TI 1 "general_operand" "")) - (clobber (match_scratch:DI 2 ""))])] + [(set (match_operand:TI 0 "general_operand" "") + (match_operand:TI 1 "general_operand" ""))] "" { rtx op1 = ia64_expand_move (operands[0], operands[1]); @@ -599,8 +600,7 @@ (define_insn_and_split "*movti_internal" [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m") - (match_operand:TI 1 "general_operand" "ri,m,r")) - (clobber (match_scratch:DI 2 "=X,&r,&r"))] + (match_operand:TI 1 "general_operand" "ri,m,r"))] "ia64_move_ok (operands[0], operands[1])" "#" "reload_completed" @@ -612,20 +612,6 @@ [(set_attr "itanium_class" "unknown") (set_attr "predicable" "no")]) -(define_expand "reload_inti" - [(parallel [(set (match_operand:TI 0 "register_operand" "=r") - (match_operand:TI 1 "memory_operand" "m")) - (clobber (match_operand:DI 2 "register_operand" "=&r"))])] - "" - "") - -(define_expand "reload_outti" - [(parallel [(set (match_operand:TI 0 "memory_operand" "=m") - (match_operand:TI 1 "register_operand" "r")) - (clobber (match_operand:DI 2 "register_operand" "=&r"))])] - "" - "") - ;; Floating Point Moves ;; ;; Note - Patterns for SF mode moves are compulsory, but @@ -764,13 +750,10 @@ [(set_attr "itanium_class" "fmisc,fld,stf")]) ;; Better code generation via insns that deal with TFmode register pairs -;; directly. -;; With no offsettable memory references, we've got to have a scratch -;; around to play with the second word. +;; directly. Same concerns apply as for TImode. (define_expand "movtf" - [(parallel [(set (match_operand:TF 0 "general_operand" "") - (match_operand:TF 1 "general_operand" "")) - (clobber (match_scratch:DI 2 ""))])] + [(set (match_operand:TF 0 "general_operand" "") + (match_operand:TF 1 "general_operand" ""))] "" { rtx op1 = ia64_expand_move (operands[0], operands[1]); @@ -781,8 +764,7 @@ (define_insn_and_split "*movtf_internal" [(set (match_operand:TF 0 "nonimmediate_operand" "=r,r,m") - (match_operand:TF 1 "general_operand" "ri,m,r")) - (clobber (match_scratch:DI 2 "=X,&r,&r"))] + (match_operand:TF 1 "general_operand" "ri,m,r"))] "ia64_move_ok (operands[0], operands[1])" "#" "reload_completed" @@ -794,19 +776,6 @@ [(set_attr "itanium_class" "unknown") (set_attr "predicable" "no")]) -(define_expand "reload_intf" - [(parallel [(set (match_operand:TF 0 "register_operand" "=r") - (match_operand:TF 1 "memory_operand" "m")) - (clobber (match_operand:DI 2 "register_operand" "=&r"))])] - "" - "") - -(define_expand "reload_outtf" - [(parallel [(set (match_operand:TF 0 "memory_operand" "=m") - (match_operand:TF 1 "register_operand" "r")) - (clobber (match_operand:DI 2 "register_operand" "=&r"))])] - "" - "") ;; :::::::::::::::::::: ;; ::