ia64.c (ia64_split_tmode, [...]): Rewrite to use POST_INC/POST_DEC/POST_MODIFY instead of a scratch pointer.
2004-01-28 Zack Weinberg <zack@codesourcery.com> Jim Wilson <wilson@specifixinc.com> * 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. From-SVN: r76798
This commit is contained in:
parent
f15f99a14e
commit
2ffe0e0241
@ -1,3 +1,14 @@
|
||||
2004-01-28 Zack Weinberg <zack@codesourcery.com>
|
||||
Jim Wilson <wilson@specifixinc.com>
|
||||
|
||||
* 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 <jh@suse.cz>
|
||||
|
||||
* 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.
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"))])]
|
||||
""
|
||||
"")
|
||||
|
||||
;; ::::::::::::::::::::
|
||||
;; ::
|
||||
|
Loading…
Reference in New Issue
Block a user