Commit b840bfb0 by Michael Meissner

Respin DI support to be combine friendly; Allow push of SF without temp reg; Fix…

Respin DI support to be combine friendly; Allow push of SF without temp reg; Fix broken i386 untyped_call

From-SVN: r8098
parent 3221f176
......@@ -378,6 +378,7 @@ find_addr_reg (addr)
abort ();
}
/* Output an insn to add the constant N to the register X. */
static void
......@@ -404,6 +405,7 @@ asm_add (n, x)
}
}
/* Output assembler code to perform a doubleword move insn
with operands OPERANDS. */
......@@ -735,6 +737,199 @@ compadr:
return "";
}
#define MAX_TMPS 2 /* max temporary registers used */
/* Output the appropriate code to move push memory on the stack */
char *
output_move_pushmem (operands, insn, length, tmp_start, n_operands)
rtx operands[];
rtx insn;
int length;
int tmp_start;
int n_operands;
{
struct {
char *load;
char *push;
rtx xops[2];
} tmp_info[MAX_TMPS];
rtx src = operands[1];
int max_tmps = 0;
int offset = 0;
int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
int stack_offset = 0;
int i, num_tmps;
rtx xops[1];
if (!offsettable_memref_p (src))
fatal_insn ("Source is not offsettable", insn);
if ((length & 3) != 0)
fatal_insn ("Pushing non-word aligned size", insn);
/* Figure out which temporary registers we have available */
for (i = tmp_start; i < n_operands; i++)
{
if (GET_CODE (operands[i]) == REG)
{
if (reg_overlap_mentioned_p (operands[i], src))
continue;
tmp_info[ max_tmps++ ].xops[1] = operands[i];
if (max_tmps == MAX_TMPS)
break;
}
}
if (max_tmps == 0)
for (offset = length - 4; offset >= 0; offset -= 4)
{
xops[0] = adj_offsettable_operand (src, offset + stack_offset);
output_asm_insn (AS1(push%L0,%0), xops);
if (stack_p)
stack_offset += 4;
}
else
for (offset = length - 4; offset >= 0; )
{
for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
{
tmp_info[num_tmps].load = AS2(mov%L0,%0,%1);
tmp_info[num_tmps].push = AS1(push%L0,%1);
tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
offset -= 4;
}
for (i = 0; i < num_tmps; i++)
output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
for (i = 0; i < num_tmps; i++)
output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
if (stack_p)
stack_offset += 4*num_tmps;
}
return "";
}
/* Output the appropriate code to move data between two memory locations */
char *
output_move_memory (operands, insn, length, tmp_start, n_operands)
rtx operands[];
rtx insn;
int length;
int tmp_start;
int n_operands;
{
struct {
char *load;
char *store;
rtx xops[3];
} tmp_info[MAX_TMPS];
rtx dest = operands[0];
rtx src = operands[1];
rtx qi_tmp = NULL_RTX;
int max_tmps = 0;
int offset = 0;
int i, num_tmps;
rtx xops[3];
if (GET_CODE (dest) == MEM
&& GET_CODE (XEXP (dest, 0)) == PRE_INC
&& XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
if (!offsettable_memref_p (src))
fatal_insn ("Source is not offsettable", insn);
if (!offsettable_memref_p (dest))
fatal_insn ("Destination is not offsettable", insn);
/* Figure out which temporary registers we have available */
for (i = tmp_start; i < n_operands; i++)
{
if (GET_CODE (operands[i]) == REG)
{
if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
qi_tmp = operands[i];
if (reg_overlap_mentioned_p (operands[i], dest))
fatal_insn ("Temporary register overlaps the destination", insn);
if (reg_overlap_mentioned_p (operands[i], src))
fatal_insn ("Temporary register overlaps the source", insn);
tmp_info[ max_tmps++ ].xops[2] = operands[i];
if (max_tmps == MAX_TMPS)
break;
}
}
if (max_tmps == 0)
fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
if ((length & 1) != 0)
{
if (!qi_tmp)
fatal_insn ("No byte register found when moving odd # of bytes.", insn);
}
while (length > 1)
{
for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)
{
if (length >= 4)
{
tmp_info[num_tmps].load = AS2(mov%L0,%1,%2);
tmp_info[num_tmps].store = AS2(mov%L0,%2,%0);
tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
offset += 4;
length -= 4;
}
else if (length >= 2)
{
tmp_info[num_tmps].load = AS2(mov%W0,%1,%2);
tmp_info[num_tmps].store = AS2(mov%W0,%2,%0);
tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
offset += 2;
length -= 2;
}
else
break;
}
for (i = 0; i < num_tmps; i++)
output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
for (i = 0; i < num_tmps; i++)
output_asm_insn (tmp_info[i].store, tmp_info[i].xops);
}
if (length == 1)
{
xops[0] = adj_offsettable_operand (dest, offset);
xops[1] = adj_offsettable_operand (src, offset);
xops[2] = qi_tmp;
output_asm_insn (AS2(mov%B0,%1,%2), xops);
output_asm_insn (AS2(mov%B0,%2,%0), xops);
}
return "";
}
int
standard_80387_constant_p (x)
......
......@@ -1704,6 +1704,8 @@ extern void output_op_from_reg ();
extern void output_to_reg ();
extern char *singlemove_string ();
extern char *output_move_double ();
extern char *output_move_memory ();
extern char *output_move_pushmem ();
extern int standard_80387_constant_p ();
extern char *output_move_const_single ();
extern int symbolic_operand ();
......
......@@ -808,6 +808,11 @@
/* Fastest way to change a 0 to a 1. */
return AS1 (inc%L0,%0);
if (flag_pic
&& GET_CODE (operands[1]) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (operands[1]))
return AS2 (lea%L0,%a1,%0);
return AS2 (mov%L0,%1,%0);
}")
......@@ -1108,9 +1113,9 @@
}")
(define_insn "movsf_push"
[(set (match_operand:SF 0 "push_operand" "=<,<,<")
(match_operand:SF 1 "general_operand" "rF,f,m"))
(clobber (match_scratch:SI 2 "=X,X,r"))]
[(set (match_operand:SF 0 "push_operand" "=<,<,<,<")
(match_operand:SF 1 "general_operand" "rF,f,m,m"))
(clobber (match_scratch:SI 2 "=X,X,r,X"))]
""
"*
{
......@@ -1134,7 +1139,7 @@
RET;
}
else if (GET_CODE (operands[1]) != MEM)
else if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != REG)
return AS1 (push%L1,%1);
else
......@@ -1301,42 +1306,11 @@
RET;
}
else if (GET_CODE (operands[1]) != MEM
|| GET_CODE (operands[2]) != REG)
else if (GET_CODE (operands[1]) != MEM)
return output_move_double (operands);
else
{
rtx low[1], high[1], xop[4];
split_di (&operands[1], 1, low, high);
xop[0] = operands[2];
xop[1] = operands[3];
xop[2] = high[0];
xop[3] = low[0];
if (GET_CODE (operands[3]) == REG)
{ /* 2 scratch registers available */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS2 (mov%L0,%3,%1), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
output_asm_insn (AS1 (push%L0,%1), xop);
}
else
{ /* 1 scratch register */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
/* account for push above */
if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[3], 0)))
xop[3] = adj_offsettable_operand (xop[3], 4);
output_asm_insn (AS2 (mov%L0,%3,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
}
RET;
}
return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);
}")
(define_insn "movdf_mem"
......@@ -1345,34 +1319,7 @@
(clobber (match_scratch:SI 2 "=&r,&r"))
(clobber (match_scratch:SI 3 "=&r,X"))]
""
"*
{
rtx low[2], high[2], xop[6];
split_di (operands, 2, low, high);
xop[0] = operands[2];
xop[1] = operands[3];
xop[2] = high[0];
xop[3] = high[1];
xop[4] = low[0];
xop[5] = low[1];
if (GET_CODE (operands[3]) == REG)
{ /* 2 scratch registers available */
output_asm_insn (AS2 (mov%L0,%5,%0), xop);
output_asm_insn (AS2 (mov%L0,%3,%1), xop);
output_asm_insn (AS2 (mov%L0,%0,%4), xop);
output_asm_insn (AS2 (mov%L0,%1,%2), xop);
}
else
{ /* 1 scratch register */
output_asm_insn (AS2 (mov%L0,%5,%0), xop);
output_asm_insn (AS2 (mov%L0,%0,%4), xop);
output_asm_insn (AS2 (mov%L0,%3,%0), xop);
output_asm_insn (AS2 (mov%L0,%0,%2), xop);
}
RET;
}")
"* return output_move_memory (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);")
;; For the purposes of regclass, prefer FLOAT_REGS.
(define_insn "movdf_normal"
......@@ -1520,51 +1467,7 @@
return output_move_double (operands);
else
{
rtx xop[5];
xop[0] = operands[2];
xop[1] = operands[3];
xop[2] = adj_offsettable_operand (operands[1], 8);
xop[3] = adj_offsettable_operand (operands[1], 4);
xop[4] = operands[1];
if (GET_CODE (operands[3]) == REG)
{ /* 2 scratch registers available */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS2 (mov%L0,%3,%1), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
output_asm_insn (AS1 (push%L0,%1), xop);
/* account for 2 pushes above */
if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[4], 0)))
xop[4] = adj_offsettable_operand (xop[4], 8);
output_asm_insn (AS2 (mov%L0,%4,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
}
else
{ /* 1 scratch register */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
/* account for 1 push above */
if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[3], 0)))
xop[3] = adj_offsettable_operand (xop[3], 4);
output_asm_insn (AS2 (mov%L0,%3,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
/* account for 2 pushes above */
if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[4], 0)))
xop[4] = adj_offsettable_operand (xop[4], 8);
output_asm_insn (AS2 (mov%L0,%4,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
}
RET;
}
return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);
}")
(define_insn "movxf_mem"
......@@ -1573,40 +1476,7 @@
(clobber (match_scratch:SI 2 "=&r,&r"))
(clobber (match_scratch:SI 3 "=&r,X"))]
""
"*
{
rtx xop[8];
xop[0] = operands[2];
xop[1] = operands[3];
xop[2] = adj_offsettable_operand (operands[1], 8);
xop[3] = adj_offsettable_operand (operands[1], 4);
xop[4] = operands[1];
xop[5] = adj_offsettable_operand (operands[0], 8);
xop[6] = adj_offsettable_operand (operands[0], 4);
xop[7] = operands[0];
if (GET_CODE (operands[3]) == REG)
{ /* 2 scratch registers available */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS2 (mov%L0,%3,%1), xop);
output_asm_insn (AS2 (mov%L5,%0,%5), xop);
output_asm_insn (AS2 (mov%L6,%1,%6), xop);
output_asm_insn (AS2 (mov%L0,%4,%0), xop);
output_asm_insn (AS2 (mov%L7,%0,%7), xop);
}
else
{ /* 1 scratch register */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS2 (mov%L0,%0,%5), xop);
output_asm_insn (AS2 (mov%L0,%3,%0), xop);
output_asm_insn (AS2 (mov%L0,%0,%6), xop);
output_asm_insn (AS2 (mov%L0,%4,%0), xop);
output_asm_insn (AS2 (mov%L7,%0,%7), xop);
}
RET;
}")
"* return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);")
(define_insn "movxf_normal"
[(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm")
......@@ -1678,34 +1548,7 @@
return AS1 (fxch,%0);
}")
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
"
{
/* Special case memory->memory moves and pushes */
if (TARGET_MOVE
&& (reload_in_progress | reload_completed) == 0
&& GET_CODE (operands[0]) == MEM
&& (GET_CODE (operands[1]) == MEM || push_operand (operands[0], DImode)))
{
rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], DImode))
? gen_movdi_push
: gen_movdi_mem;
emit_insn ((*genfunc) (operands[0], operands[1]));
DONE;
}
}")
(define_insn "movdi_push_nomove"
[(set (match_operand:DI 0 "push_operand" "=<")
(match_operand:DI 1 "general_operand" "roiF"))]
"!TARGET_MOVE"
"* return output_move_double (operands);")
(define_insn "movdi_push"
(define_insn ""
[(set (match_operand:DI 0 "push_operand" "=<,<,<,<")
(match_operand:DI 1 "general_operand" "riF,o,o,o"))
(clobber (match_scratch:SI 2 "=X,&r,&r,X"))
......@@ -1713,85 +1556,29 @@
""
"*
{
if (GET_CODE (operands[1]) != MEM
|| GET_CODE (operands[2]) != REG)
if (GET_CODE (operands[1]) != MEM)
return output_move_double (operands);
else
{
rtx low[1], high[1], xop[4];
split_di (&operands[1], 1, low, high);
xop[0] = operands[2];
xop[1] = operands[3];
xop[2] = high[0];
xop[3] = low[0];
if (GET_CODE (operands[3]) == REG)
{ /* 2 scratch registers available */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS2 (mov%L0,%3,%1), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
output_asm_insn (AS1 (push%L0,%1), xop);
}
else
{ /* 1 scratch register */
output_asm_insn (AS2 (mov%L0,%2,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
/* account for push above */
if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[3], 0)))
xop[3] = adj_offsettable_operand (xop[3], 4);
output_asm_insn (AS2 (mov%L0,%3,%0), xop);
output_asm_insn (AS1 (push%L0,%0), xop);
}
RET;
}
return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
}")
(define_insn "movdi_mem"
[(set (match_operand:DI 0 "memory_operand" "=o,o")
(match_operand:DI 1 "memory_operand" "o,o"))
(clobber (match_scratch:SI 2 "=&r,&r"))
(clobber (match_scratch:SI 3 "=&r,X"))]
(define_insn "movdi"
[(set (match_operand:DI 0 "general_operand" "=o,o,r,rm")
(match_operand:DI 1 "general_operand" "o,o,m,riF"))
(clobber (match_scratch:SI 2 "=&r,&r,X,X"))
(clobber (match_scratch:SI 3 "=&r,X,X,X"))]
""
"*
{
rtx low[2], high[2], xop[6];
split_di (operands, 2, low, high);
xop[0] = operands[2];
xop[1] = operands[3];
xop[2] = high[0];
xop[3] = high[1];
xop[4] = low[0];
xop[5] = low[1];
if (GET_CODE (operands[3]) == REG)
{ /* 2 scratch registers available */
output_asm_insn (AS2 (mov%L0,%5,%0), xop);
output_asm_insn (AS2 (mov%L0,%3,%1), xop);
output_asm_insn (AS2 (mov%L0,%0,%4), xop);
output_asm_insn (AS2 (mov%L0,%1,%2), xop);
}
if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
return output_move_double (operands);
else
{ /* 1 scratch register */
output_asm_insn (AS2 (mov%L0,%5,%0), xop);
output_asm_insn (AS2 (mov%L0,%0,%4), xop);
output_asm_insn (AS2 (mov%L0,%3,%0), xop);
output_asm_insn (AS2 (mov%L0,%0,%2), xop);
}
RET;
return output_move_memory (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
}")
(define_insn "movdi_normal"
[(set (match_operand:DI 0 "general_operand" "=r,rm")
(match_operand:DI 1 "general_operand" "m,riF"))]
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"* return output_move_double (operands);")
;;- conversion instructions
;;- NONE
......@@ -5296,126 +5083,42 @@
"!HALF_PIC_P ()"
"call %P1")
;; Call subroutine returning any type.
(define_expand "untyped_call"
[(parallel [(call (match_operand:QI 0 "indirect_operand" "")
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
(match_operand:BLK 1 "memory_operand" "")
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
"
{
rtx addr;
int i;
if (flag_pic)
current_function_uses_pic_offset_table = 1;
/* With half-pic, force the address into a register. */
addr = XEXP (operands[0], 0);
if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
XEXP (operands[0], 0) = force_reg (Pmode, addr);
operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
if (! expander_call_insn_operand (operands[1], QImode))
operands[1]
= change_address (operands[1], VOIDmode,
copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
}")
emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
(define_insn ""
[(call (match_operand:QI 0 "call_insn_operand" "m")
(const_int 0))
(match_operand:DI 1 "memory_operand" "o")
(match_operand 2 "" "")]
""
"*
{
rtx addr = operands[1];
if (GET_CODE (operands[0]) == MEM
&& ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
operands[0] = XEXP (operands[0], 0);
output_asm_insn (AS1 (call,%*%0), operands);
rtx set = XVECEXP (operands[2], 0, i);
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
else
output_asm_insn (AS1 (call,%P0), operands);
operands[2] = gen_rtx (REG, SImode, 0);
output_asm_insn (AS2 (mov%L2,%2,%1), operands);
operands[2] = gen_rtx (REG, SImode, 1);
operands[1] = adj_offsettable_operand (addr, 4);
output_asm_insn (AS2 (mov%L2,%2,%1), operands);
operands[1] = adj_offsettable_operand (addr, 8);
return AS1 (fnsave,%1);
}")
(define_insn ""
[(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
(const_int 0))
(match_operand:DI 1 "memory_operand" "o")
(match_operand 2 "" "")]
"!HALF_PIC_P ()"
"*
{
rtx addr = operands[1];
output_asm_insn (AS1 (call,%P0), operands);
operands[2] = gen_rtx (REG, SImode, 0);
output_asm_insn (AS2 (mov%L2,%2,%1), operands);
operands[2] = gen_rtx (REG, SImode, 1);
operands[1] = adj_offsettable_operand (addr, 4);
output_asm_insn (AS2 (mov%L2,%2,%1), operands);
operands[1] = adj_offsettable_operand (addr, 8);
return AS1 (fnsave,%1);
}")
;; We use fnsave and frstor to save and restore the floating point result.
;; These are expensive instructions and require a large space to save the
;; FPU state. An more complicated alternative is to use fnstenv to store
;; the FPU environment and test whether the stack top is valid. Store the
;; result of the test, and if it is valid, pop and save the value. The
;; untyped_return would check the test and optionally push the saved value.
(define_expand "untyped_return"
[(match_operand:BLK 0 "memory_operand" "")
(match_operand 1 "" "")]
""
"
{
rtx valreg1 = gen_rtx (REG, SImode, 0);
rtx valreg2 = gen_rtx (REG, SImode, 1);
rtx result = operands[0];
/* Restore the FPU state. */
emit_insn (gen_update_return (change_address (result, SImode,
plus_constant (XEXP (result, 0),
8))));
/* Reload the function value registers. */
emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0)));
emit_move_insn (valreg2,
change_address (result, SImode,
plus_constant (XEXP (result, 0), 4)));
/* Put USE insns before the return. */
emit_insn (gen_rtx (USE, VOIDmode, valreg1));
emit_insn (gen_rtx (USE, VOIDmode, valreg2));
/* Construct the return. */
expand_null_return ();
/* The optimizer does not know that the call sets the function value
registers we stored in the result block. We avoid problems by
claiming that all hard registers are used and clobbered at this
point. */
emit_insn (gen_blockage ());
DONE;
}")
(define_insn "update_return"
[(unspec:SI [(match_operand:SI 0 "memory_operand" "m")] 0)]
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 0)]
""
"frstor %0")
"")
;; Insn emitted into the body of a function to return from a function.
;; This is only done if the function's epilogue is known to be simple.
......
......@@ -68,9 +68,7 @@ nil_method(id receiver, SEL op, ...)
}
/* Given a class and selector, return the selector's implementation. */
#ifndef i386
__inline__ /* this is broken on i386... */
#endif
__inline__
IMP
get_imp (Class* class, SEL sel)
{
......
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