Commit 68944452 by Jeff Law

pa.md (abssi2): New pattern.

	* pa.md (abssi2): New pattern.

	* pa.c (secondary_reload_class): Loads from reg+d addresses into
	FP registers don't need secondary reloads.
	* pa.h: Delete soem #if 0 code.  Update some comments.
	(EXTRA_CONSTRAINT, case 'Q'): Only accept valid memory addresses.

        * pa.h (RTX_COSTS): Tege's rewrite.

	* pa.c (hppa_legitimize_address): Generate unscaled indexed
	addressing for (plus (symbol_ref) (reg)).
	(emit_move_sequence): Set REGNO_POINTER_FLAG appropriately
	to encourage unscaled indexing modes.
	(basereg_operand): New function for unscaled index address support.
	* pa.md (unscaled indexing patterns): New patterns for unscaled
	index address support.

	* pa.h (MOVE_RATIO): Define.
	* pa.md (movstrsi expander): Refine tests for when to use the
	library routine instead of an inlined loop copy.  Provide an
	additional scratch register for use in the inlined loop copy.
	(movstrsi_internal): Name the pattern for ease of use.  Add
	additional scratch register.
	* pa.c (output_block_move): Greatly simplify.  Use 2X unrolled
	copy loops to improve performance.
	(compute_movstrsi_length): Corresponding changes.

	* pa.c (print_operand): Handle 'y' case for reversed FP
	comparisons.  Delete some #if 0 code.  Fix various comment typos.
	* pa.md (fcmp patterns): Try and reverse the comparison to avoid
	useless add,tr insns.

From-SVN: r10609
parent 926d1ca5
...@@ -637,6 +637,16 @@ hppa_legitimize_address (x, oldx, mode) ...@@ -637,6 +637,16 @@ hppa_legitimize_address (x, oldx, mode)
if (GET_CODE (x) == CONST) if (GET_CODE (x) == CONST)
x = XEXP (x, 0); x = XEXP (x, 0);
/* Special case. Get the SYMBOL_REF into a register and use indexing.
That should always be safe. */
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
{
rtx reg = force_reg (SImode, XEXP (x, 1));
return force_reg (SImode, gen_rtx (PLUS, SImode, reg, XEXP (x, 0)));
}
/* Note we must reject symbols which represent function addresses /* Note we must reject symbols which represent function addresses
since the assembler/linker can't handle arithmetic on plabels. */ since the assembler/linker can't handle arithmetic on plabels. */
if (GET_CODE (x) == PLUS if (GET_CODE (x) == PLUS
...@@ -793,7 +803,7 @@ emit_move_sequence (operands, mode, scratch_reg) ...@@ -793,7 +803,7 @@ emit_move_sequence (operands, mode, scratch_reg)
/* Handle secondary reloads for loads/stores of FP registers from /* Handle secondary reloads for loads/stores of FP registers from
REG+D addresses where D does not fit in 5 bits, including REG+D addresses where D does not fit in 5 bits, including
(subreg (mem (addr)) cases. */ (subreg (mem (addr))) cases. */
if (fp_reg_operand (operand0, mode) if (fp_reg_operand (operand0, mode)
&& ((GET_CODE (operand1) == MEM && ((GET_CODE (operand1) == MEM
&& ! memory_address_p (DFmode, XEXP (operand1, 0))) && ! memory_address_p (DFmode, XEXP (operand1, 0)))
...@@ -975,9 +985,9 @@ emit_move_sequence (operands, mode, scratch_reg) ...@@ -975,9 +985,9 @@ emit_move_sequence (operands, mode, scratch_reg)
operands[1] = force_const_mem (mode, operand1); operands[1] = force_const_mem (mode, operand1);
emit_move_sequence (operands, mode, temp); emit_move_sequence (operands, mode, temp);
} }
/* Likewise for (const (plus (symbol) (const_int)) when generating /* Likewise for (const (plus (symbol) (const_int))) when
pic code during or after reload and const_int will not fit generating pic code during or after reload and const_int
in 14 bits. */ will not fit in 14 bits. */
else if (GET_CODE (operand1) == CONST else if (GET_CODE (operand1) == CONST
&& GET_CODE (XEXP (operand1, 0)) == PLUS && GET_CODE (XEXP (operand1, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (operand1, 0), 1)) == CONST_INT && GET_CODE (XEXP (XEXP (operand1, 0), 1)) == CONST_INT
...@@ -1008,6 +1018,14 @@ emit_move_sequence (operands, mode, scratch_reg) ...@@ -1008,6 +1018,14 @@ emit_move_sequence (operands, mode, scratch_reg)
else else
temp = gen_reg_rtx (mode); temp = gen_reg_rtx (mode);
/* Loading a SYMBOL_REF into a register makes that register
safe to be used as the base in an indexed address.
Don't mark hard registers though. That loses. */
if (REGNO (operand0) >= FIRST_PSEUDO_REGISTER)
REGNO_POINTER_FLAG (REGNO (operand0)) = 1;
if (REGNO (temp) >= FIRST_PSEUDO_REGISTER)
REGNO_POINTER_FLAG (REGNO (temp)) = 1;
if (ishighonly) if (ishighonly)
set = gen_rtx (SET, mode, operand0, temp); set = gen_rtx (SET, mode, operand0, temp);
else else
...@@ -1457,18 +1475,13 @@ find_addr_reg (addr) ...@@ -1457,18 +1475,13 @@ find_addr_reg (addr)
/* Emit code to perform a block move. /* Emit code to perform a block move.
Restriction: If the length argument is non-constant, alignment
must be 4.
OPERANDS[0] is the destination pointer as a REG, clobbered. OPERANDS[0] is the destination pointer as a REG, clobbered.
OPERANDS[1] is the source pointer as a REG, clobbered. OPERANDS[1] is the source pointer as a REG, clobbered.
if SIZE_IS_CONSTANT OPERANDS[2] is a register for temporary storage.
OPERANDS[2] is a register for temporary storage. OPERANDS[4] is the size as a CONST_INT
OPERANDS[4] is the size as a CONST_INT
else
OPERANDS[2] is a REG which will contain the size, clobbered.
OPERANDS[3] is a register for temporary storage. OPERANDS[3] is a register for temporary storage.
OPERANDS[5] is the alignment safe to use, as a CONST_INT. */ OPERANDS[5] is the alignment safe to use, as a CONST_INT.
OPERNADS[6] is another temporary register. */
char * char *
output_block_move (operands, size_is_constant) output_block_move (operands, size_is_constant)
...@@ -1476,153 +1489,94 @@ output_block_move (operands, size_is_constant) ...@@ -1476,153 +1489,94 @@ output_block_move (operands, size_is_constant)
int size_is_constant; int size_is_constant;
{ {
int align = INTVAL (operands[5]); int align = INTVAL (operands[5]);
unsigned long n_bytes; unsigned long n_bytes = INTVAL (operands[4]);
/* We can't move more than four bytes at a time because the PA /* We can't move more than four bytes at a time because the PA
has no longer integer move insns. (Could use fp mem ops?) */ has no longer integer move insns. (Could use fp mem ops?) */
if (align > 4) if (align > 4)
align = 4; align = 4;
if (size_is_constant) /* Note that we know each loop below will execute at least twice
(else we would have open-coded the copy). */
switch (align)
{ {
unsigned long offset; case 4:
rtx temp; /* Pre-adjust the loop counter. */
operands[4] = GEN_INT (n_bytes - 8);
n_bytes = INTVAL (operands[4]); output_asm_insn ("ldi %4,%2", operands);
if (n_bytes == 0)
return ""; /* Copying loop. */
output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
if (align >= 4) output_asm_insn ("ldws,ma 4(0,%1),%6", operands);
{ output_asm_insn ("stws,ma %3,4(0,%0)", operands);
/* Don't unroll too large blocks. */ output_asm_insn ("addib,>= -8,%2,.-12", operands);
if (n_bytes > 32) output_asm_insn ("stws,ma %6,4(0,%0)", operands);
goto copy_with_loop;
/* Handle the residual. There could be up to 7 bytes of
/* Read and store using two registers, and hide latency residual to copy! */
by deferring the stores until three instructions after if (n_bytes % 8 != 0)
the corresponding load. The last load insn will read {
the entire word were the last bytes are, possibly past operands[4] = GEN_INT (n_bytes % 4);
the end of the source block, but since loads are aligned, if (n_bytes % 8 >= 4)
this is harmless. */
output_asm_insn ("ldws,ma 4(0,%1),%2", operands);
for (offset = 4; offset < n_bytes; offset += 4)
{
output_asm_insn ("ldws,ma 4(0,%1),%3", operands); output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
output_asm_insn ("stws,ma %2,4(0,%0)", operands); if (n_bytes % 4 != 0)
output_asm_insn ("ldw 0(0,%1),%6", operands);
if (n_bytes % 8 >= 4)
output_asm_insn ("stws,ma %3,4(0,%0)", operands);
if (n_bytes % 4 != 0)
output_asm_insn ("stbys,e %6,%4(0,%0)", operands);
}
return "";
temp = operands[2]; case 2:
operands[2] = operands[3]; /* Pre-adjust the loop counter. */
operands[3] = temp; operands[4] = GEN_INT (n_bytes - 4);
} output_asm_insn ("ldi %4,%2", operands);
if (n_bytes % 4 == 0)
/* Store the last word. */
output_asm_insn ("stw %2,0(0,%0)", operands);
else
{
/* Store the last, partial word. */
operands[4] = GEN_INT (n_bytes % 4);
output_asm_insn ("stbys,e %2,%4(0,%0)", operands);
}
return "";
}
if (align >= 2 && n_bytes >= 2) /* Copying loop. */
{ output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);
output_asm_insn ("ldhs,ma 2(0,%1),%2", operands); output_asm_insn ("ldhs,ma 2(0,%1),%6", operands);
output_asm_insn ("sths,ma %3,2(0,%0)", operands);
output_asm_insn ("addib,>= -4,%2,.-12", operands);
output_asm_insn ("sths,ma %6,2(0,%0)", operands);
for (offset = 2; offset + 2 <= n_bytes; offset += 2) /* Handle the residual. */
{ if (n_bytes % 4 != 0)
{
if (n_bytes % 4 >= 2)
output_asm_insn ("ldhs,ma 2(0,%1),%3", operands); output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);
output_asm_insn ("sths,ma %2,2(0,%0)", operands); if (n_bytes % 2 != 0)
output_asm_insn ("ldb 0(0,%1),%6", operands);
if (n_bytes % 4 >= 2)
output_asm_insn ("sths,ma %3,2(0,%0)", operands);
if (n_bytes % 2 != 0)
output_asm_insn ("stb %6,0(0,%0)", operands);
}
return "";
temp = operands[2]; case 1:
operands[2] = operands[3]; /* Pre-adjust the loop counter. */
operands[3] = temp; operands[4] = GEN_INT (n_bytes - 2);
} output_asm_insn ("ldi %4,%2", operands);
if (n_bytes % 2 != 0)
output_asm_insn ("ldb 0(0,%1),%3", operands);
output_asm_insn ("sths,ma %2,2(0,%0)", operands); /* Copying loop. */
output_asm_insn ("ldbs,ma 1(0,%1),%3", operands);
output_asm_insn ("ldbs,ma 1(0,%1),%6", operands);
output_asm_insn ("stbs,ma %3,1(0,%0)", operands);
output_asm_insn ("addib,>= -2,%2,.-12", operands);
output_asm_insn ("stbs,ma %6,1(0,%0)", operands);
if (n_bytes % 2 != 0) /* Handle the residual. */
if (n_bytes % 2 != 0)
{
output_asm_insn ("ldb 0(0,%1),%3", operands);
output_asm_insn ("stb %3,0(0,%0)", operands); output_asm_insn ("stb %3,0(0,%0)", operands);
}
return "";
return ""; default:
} abort ();
output_asm_insn ("ldbs,ma 1(0,%1),%2", operands);
for (offset = 1; offset + 1 <= n_bytes; offset += 1)
{
output_asm_insn ("ldbs,ma 1(0,%1),%3", operands);
output_asm_insn ("stbs,ma %2,1(0,%0)", operands);
temp = operands[2];
operands[2] = operands[3];
operands[3] = temp;
}
output_asm_insn ("stb %2,0(0,%0)", operands);
return "";
}
if (align != 4)
abort();
copy_with_loop:
if (size_is_constant)
{
/* Size is compile-time determined, and also not
very small (such small cases are handled above). */
operands[4] = GEN_INT (n_bytes - 4);
output_asm_insn ("ldo %4(0),%2", operands);
}
else
{
/* Decrement counter by 4, and if it becomes negative, jump past the
word copying loop. */
output_asm_insn ("addib,<,n -4,%2,.+16", operands);
}
/* Copying loop. Note that the first load is in the annulled delay slot
of addib. Is it OK on PA to have a load in a delay slot, i.e. is a
possible page fault stopped in time? */
output_asm_insn ("ldws,ma 4(0,%1),%3", operands);
output_asm_insn ("addib,>= -4,%2,.-4", operands);
output_asm_insn ("stws,ma %3,4(0,%0)", operands);
/* The counter is negative, >= -4. The remaining number of bytes are
determined by the two least significant bits. */
if (size_is_constant)
{
if (n_bytes % 4 != 0)
{
/* Read the entire word of the source block tail. */
output_asm_insn ("ldw 0(0,%1),%3", operands);
operands[4] = GEN_INT (n_bytes % 4);
output_asm_insn ("stbys,e %3,%4(0,%0)", operands);
}
}
else
{
/* Add 4 to counter. If it becomes zero, we're done. */
output_asm_insn ("addib,=,n 4,%2,.+16", operands);
/* Read the entire word of the source block tail. (Also this
load is in an annulled delay slot.) */
output_asm_insn ("ldw 0(0,%1),%3", operands);
/* Make %0 point at the first byte after the destination block. */
output_asm_insn ("addl %2,%0,%0", operands);
/* Store the leftmost bytes, up to, but not including, the address
in %0. */
output_asm_insn ("stbys,e %3,0(0,%0)", operands);
} }
return "";
} }
/* Count the number of insns necessary to handle this block move. /* Count the number of insns necessary to handle this block move.
...@@ -1635,106 +1589,33 @@ compute_movstrsi_length (insn) ...@@ -1635,106 +1589,33 @@ compute_movstrsi_length (insn)
rtx insn; rtx insn;
{ {
rtx pat = PATTERN (insn); rtx pat = PATTERN (insn);
int size_is_constant;
int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0)); int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0));
unsigned long n_bytes; unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0));
int insn_count = 0; unsigned int n_insns = 0;
if (GET_CODE (XEXP (XVECEXP (pat, 0, 5), 0)) == CONST_INT)
{
size_is_constant = 1;
n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0));
}
else
{
size_is_constant = 0;
n_bytes = 0;
}
/* We can't move more than four bytes at a time because the PA /* We can't move more than four bytes at a time because the PA
has no longer integer move insns. (Could use fp mem ops?) */ has no longer integer move insns. (Could use fp mem ops?) */
if (align > 4) if (align > 4)
align = 4; align = 4;
if (size_is_constant) /* The basic opying loop. */
{ n_insns = 6;
unsigned long offset;
if (n_bytes == 0)
return 0;
if (align >= 4)
{
/* Don't unroll too large blocks. */
if (n_bytes > 32)
goto copy_with_loop;
/* first load */
insn_count = 1;
/* Count the unrolled insns. */
for (offset = 4; offset < n_bytes; offset += 4)
insn_count += 2;
/* Count last store or partial store. */
insn_count += 1;
return insn_count * 4;
}
if (align >= 2 && n_bytes >= 2)
{
/* initial load. */
insn_count = 1;
/* Unrolled loop. */
for (offset = 2; offset + 2 <= n_bytes; offset += 2)
insn_count += 2;
/* ??? odd load/store */
if (n_bytes % 2 != 0)
insn_count += 2;
/* ??? final store from loop. */
insn_count += 1;
return insn_count * 4; /* Residuals. */
} if (n_bytes % (2 * align) != 0)
/* First load. */
insn_count = 1;
/* The unrolled loop. */
for (offset = 1; offset + 1 <= n_bytes; offset += 1)
insn_count += 2;
/* Final store. */
insn_count += 1;
return insn_count * 4;
}
if (align != 4)
abort();
copy_with_loop:
/* setup for constant and non-constant case. */
insn_count = 1;
/* The copying loop. */
insn_count += 3;
/* The counter is negative, >= -4. The remaining number of bytes are
determined by the two least significant bits. */
if (size_is_constant)
{ {
if (n_bytes % 4 != 0) /* Any residual caused by unrolling the copy loop. */
insn_count += 2; if (n_bytes % (2 * align) > align)
n_insns += 1;
/* Any residual because the number of bytes was not a
multiple of the alignment. */
if (n_bytes % align != 0)
n_insns += 1;
} }
else
insn_count += 4; /* Lengths are expressed in bytes now; each insn is 4 bytes. */
return insn_count * 4; return n_insns * 4;
} }
...@@ -2363,7 +2244,7 @@ hppa_expand_prologue() ...@@ -2363,7 +2244,7 @@ hppa_expand_prologue()
even be more efficient. even be more efficient.
Avoid this if the callee saved register wasn't used (these are Avoid this if the callee saved register wasn't used (these are
leaf functions. */ leaf functions). */
if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM_SAVED]) if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM_SAVED])
emit_move_insn (gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM_SAVED), emit_move_insn (gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM_SAVED),
gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM)); gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM));
...@@ -2511,9 +2392,8 @@ hppa_expand_epilogue () ...@@ -2511,9 +2392,8 @@ hppa_expand_epilogue ()
load_reg (2, - 20, STACK_POINTER_REGNUM); load_reg (2, - 20, STACK_POINTER_REGNUM);
} }
/* Reset stack pointer (and possibly frame pointer). The stack */ /* Reset stack pointer (and possibly frame pointer). The stack
/* pointer is initially set to fp + 64 to avoid a race condition. pointer is initially set to fp + 64 to avoid a race condition. */
??? What race condition?!? */
else if (frame_pointer_needed) else if (frame_pointer_needed)
{ {
/* Emit a blockage insn here to keep these insns from being moved /* Emit a blockage insn here to keep these insns from being moved
...@@ -3004,6 +2884,27 @@ print_operand (file, x, code) ...@@ -3004,6 +2884,27 @@ print_operand (file, x, code)
abort (); abort ();
} }
return; return;
/* Reversed floating point comparison. Need special conditions to
deal with NaNs properly. */
case 'y':
switch (GET_CODE (x))
{
case EQ:
fprintf (file, "?="); break;
case NE:
fprintf (file, "!?="); break;
case GT:
fprintf (file, "!<="); break;
case GE:
fprintf (file, "!<"); break;
case LT:
fprintf (file, "!>="); break;
case LE:
fprintf (file, "!>"); break;
default:
abort ();
}
return;
case 'S': /* Condition, operands are (S)wapped. */ case 'S': /* Condition, operands are (S)wapped. */
switch (GET_CODE (x)) switch (GET_CODE (x))
{ {
...@@ -3161,30 +3062,6 @@ print_operand (file, x, code) ...@@ -3161,30 +3062,6 @@ print_operand (file, x, code)
break; break;
} }
} }
#if 0
/* The code here is completely wrong. It attempts to extract parts of
a CONST_DOUBLE which is wrong since REAL_ARITHMETIC is defined, and it
extracts the wrong indices (0 instead of 2 and 1 instead of 3) using
the wrong macro (XINT instead of XWINT).
Just disable it for now, since the code will never be used anyway! */
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
{
union { double d; int i[2]; } u;
union { float f; int i; } u1;
u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
u1.f = u.d;
if (code == 'f')
fprintf (file, "0r%.9g", u1.f);
else
fprintf (file, "0x%x", u1.i);
}
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
{
union { double d; int i[2]; } u;
u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1);
fprintf (file, "0r%.20g", u.d);
}
#endif
else else
output_addr_const (file, x); output_addr_const (file, x);
} }
...@@ -3527,12 +3404,6 @@ secondary_reload_class (class, mode, in) ...@@ -3527,12 +3404,6 @@ secondary_reload_class (class, mode, in)
if (GET_CODE (in) == SUBREG) if (GET_CODE (in) == SUBREG)
in = SUBREG_REG (in); in = SUBREG_REG (in);
if (FP_REG_CLASS_P (class)
&& GET_CODE (in) == MEM
&& !memory_address_p (DFmode, XEXP (in, 0))
&& memory_address_p (SImode, XEXP (in, 0)))
return GENERAL_REGS;
return NO_REGS; return NO_REGS;
} }
...@@ -4431,6 +4302,38 @@ shadd_operand (op, mode) ...@@ -4431,6 +4302,38 @@ shadd_operand (op, mode)
return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op))); return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op)));
} }
/* Return 1 if OP is valid as a base register in a reg + reg address. */
int
basereg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
/* Once reload has started everything is considered valid. Reload should
only create indexed addresses using the stack/frame pointer, and any
others were checked for validity when created by the combine pass.
Also allow any register when TARGET_NO_SPACE_REGS is in effect since
we don't have to worry about the braindamaged implicit space register
selection using the basereg only (rather than effective address)
screwing us over. */
if (TARGET_NO_SPACE_REGS || reload_in_progress || reload_completed)
return (GET_CODE (op) == REG || GET_CODE (op) == CONST_INT);
/* Stack and frame pointers are always OK for indexing. */
if (op == stack_pointer_rtx || op == frame_pointer_rtx)
return 1;
/* The only other valid OPs are pseudo registers with
REGNO_POINTER_FLAG set. */
if (GET_CODE (op) != REG
|| REGNO (op) < FIRST_PSEUDO_REGISTER
|| ! register_operand (op, mode))
return 0;
return REGNO_POINTER_FLAG (REGNO (op));
}
/* Return 1 if this operand is anything other than a hard register. */ /* Return 1 if this operand is anything other than a hard register. */
int int
......
...@@ -1309,10 +1309,6 @@ extern struct rtx_def *hppa_builtin_saveregs (); ...@@ -1309,10 +1309,6 @@ extern struct rtx_def *hppa_builtin_saveregs ();
these things in insns and then not re-recognize the insns, causing these things in insns and then not re-recognize the insns, causing
constrain_operands to fail. constrain_operands to fail.
Also note `Q' accepts any memory operand during the reload pass.
This includes out-of-range displacements in reg+d addressing.
This makes for better code. (??? For 2.5 address this issue).
`R' is unused. `R' is unused.
`S' is unused. `S' is unused.
...@@ -1321,8 +1317,6 @@ extern struct rtx_def *hppa_builtin_saveregs (); ...@@ -1321,8 +1317,6 @@ extern struct rtx_def *hppa_builtin_saveregs ();
#define EXTRA_CONSTRAINT(OP, C) \ #define EXTRA_CONSTRAINT(OP, C) \
((C) == 'Q' ? \ ((C) == 'Q' ? \
(IS_RELOADING_PSEUDO_P (OP) \ (IS_RELOADING_PSEUDO_P (OP) \
|| (GET_CODE (OP) == MEM \
&& reload_in_progress) \
|| (GET_CODE (OP) == MEM \ || (GET_CODE (OP) == MEM \
&& memory_address_p (GET_MODE (OP), XEXP (OP, 0))\ && memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
&& ! symbolic_memory_operand (OP, VOIDmode))) \ && ! symbolic_memory_operand (OP, VOIDmode))) \
...@@ -1571,6 +1565,11 @@ while (0) ...@@ -1571,6 +1565,11 @@ while (0)
in one reasonably fast instruction. */ in one reasonably fast instruction. */
#define MOVE_MAX 8 #define MOVE_MAX 8
/* Higher than the default as we prefer to use simple move insns
(better scheduling and delay slot filling) and because our
built-in block move is really a 2X unrolled loop. */
#define MOVE_RATIO 4
/* Define if operations between registers always perform the operation /* Define if operations between registers always perform the operation
on the full register even if a narrower mode is specified. */ on the full register even if a narrower mode is specified. */
#define WORD_REGISTER_OPERATIONS #define WORD_REGISTER_OPERATIONS
...@@ -1685,22 +1684,28 @@ while (0) ...@@ -1685,22 +1684,28 @@ while (0)
switch on CODE. The purpose for the cost of MULT is to encourage switch on CODE. The purpose for the cost of MULT is to encourage
`synth_mult' to find a synthetic multiply when reasonable. */ `synth_mult' to find a synthetic multiply when reasonable. */
#define RTX_COSTS(X,CODE,OUTER_CODE) \ #define RTX_COSTS(X,CODE,OUTER_CODE) \
case MULT: \ case MULT: \
return (TARGET_SNAKE && ! TARGET_DISABLE_FPREGS \ if (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \
&& ! TARGET_SOFT_FLOAT \ return COSTS_N_INSNS (3); \
? COSTS_N_INSNS (8) : COSTS_N_INSNS (20)); \ return (TARGET_SNAKE && ! TARGET_DISABLE_FPREGS && ! TARGET_SOFT_FLOAT) \
case DIV: \ ? COSTS_N_INSNS (8) : COSTS_N_INSNS (20); \
case UDIV: \ case DIV: \
case MOD: \ if (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \
case UMOD: \ return COSTS_N_INSNS (14); \
return COSTS_N_INSNS (60); \ case UDIV: \
case PLUS: \ case MOD: \
if (GET_CODE (XEXP (X, 0)) == MULT \ case UMOD: \
&& shadd_operand (XEXP (XEXP (X, 0), 1), VOIDmode)) \ return COSTS_N_INSNS (60); \
return (2 + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \ case PLUS: /* this includes shNadd insns */ \
+ rtx_cost (XEXP (X, 1), OUTER_CODE)); \ case MINUS: \
break; if (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \
return COSTS_N_INSNS (3); \
return COSTS_N_INSNS (1); \
case ASHIFT: \
case ASHIFTRT: \
case LSHIFTRT: \
return COSTS_N_INSNS (1);
/* Adjust the cost of dependencies. */ /* Adjust the cost of dependencies. */
...@@ -2154,41 +2159,6 @@ extern struct rtx_def *legitimize_pic_address (); ...@@ -2154,41 +2159,6 @@ extern struct rtx_def *legitimize_pic_address ();
extern struct rtx_def *gen_cmp_fp (); extern struct rtx_def *gen_cmp_fp ();
extern void hppa_encode_label (); extern void hppa_encode_label ();
#if 0
#define PREDICATE_CODES \
{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"reg_or_cint_move_operand", {SUBREG, REG, CONST_INT}}, \
{"arith_operand", {SUBREG, REG, CONST_INT}}, \
{"arith32_operand", {SUBREG, REG, CONST_INT}}, \
{"arith11_operand", {SUBREG, REG, CONST_INT}}, \
{"arith5_operand", {SUBREG, REG, CONST_INT}}, \
{"pre_cint_operand", {CONST_INT}}, \
{"post_cint_operand", {CONST_INT}}, \
{"int5_operand", {CONST_INT}}, \
{"uint5_operand", {CONST_INT}}, \
{"uint32_operand", {CONST_INT}}, \
{"int11_operand", {CONST_INT}}, \
{"and_operand", {SUBREG, REG, CONST_INT}}, \
{"ior_operand", {CONST_INT}}, \
{"lhs_lshift_operand", {SUBREG, REG, CONST_INT}}, \
{"lhs_lshift_cint_operand", {CONST_INT}}, \
{"plus_xor_ior_operator", {PLUS, XOR, IOR}}, \
{"shadd_operand", {CONST_INT}}, \
{"eq_neq_comparison_operator", {EQ, NE}}, \
{"movb_comparison_operator", {EQ, NE, LT, GE}}, \
{"pc_or_label_operand", {LABEL_REF, PC}}, \
{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
{"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
{"move_operand", {SUBREG, REG, CONST_INT, MEM}}, \
{"pic_label_operand", {LABEL_REF, CONST}}, \
{"function_label_operand", {SYMBOL_REF}}, \
{"reg_or_0_or_nonsymb_mem_operand", {SUBREG, REG, CONST_INT, \
CONST_DOUBLE, MEM}}, \
{"div_operand", {REG, CONST_INT}}, \
{"call_operand_address", {SYMBOL_REF, LABEL_REF, CONST_INT, \
CONST_DOUBLE, CONST, HIGH}},
#endif
/* We want __gcc_plt_call to appear in every program built by /* We want __gcc_plt_call to appear in every program built by
gcc, so we make a reference to it out of __main. gcc, so we make a reference to it out of __main.
We use the asm statement to fool the optimizer into not We use the asm statement to fool the optimizer into not
......
...@@ -386,7 +386,71 @@ ...@@ -386,7 +386,71 @@
[(match_operand:SF 0 "reg_or_0_operand" "fG") [(match_operand:SF 0 "reg_or_0_operand" "fG")
(match_operand:SF 1 "reg_or_0_operand" "fG")]))] (match_operand:SF 1 "reg_or_0_operand" "fG")]))]
"! TARGET_SOFT_FLOAT" "! TARGET_SOFT_FLOAT"
"fcmp,sgl,%Y2 %r0,%r1" "*
{
rtx next_insn;
/* See if this is later used in a reversed FP branch. If so, reverse our
condition and the branch. Doing so avoids a useless add,tr.
Don't do this if fcmp is in a delay slot since it's too much of a
headache to track down things on multiple paths. */
if (dbr_sequence_length ())
next_insn = NULL;
else
next_insn = NEXT_INSN (insn);
while (next_insn)
{
/* Jumps, calls and labels stop our search. */
if (GET_CODE (next_insn) == JUMP_INSN
|| GET_CODE (next_insn) == CALL_INSN
|| GET_CODE (next_insn) == CODE_LABEL)
break;
/* As does another fcmp insn. */
if (GET_CODE (next_insn) == INSN
&& GET_CODE (PATTERN (next_insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (next_insn))) == REG
&& REGNO (SET_DEST (PATTERN (next_insn))) == 0)
break;
if (GET_CODE (next_insn) == INSN
&& GET_CODE (PATTERN (next_insn)) == SEQUENCE)
next_insn = XVECEXP (PATTERN (next_insn), 0, 0);
else
next_insn = NEXT_INSN (next_insn);
}
/* Is NEXT_INSN a branch? */
if (next_insn
&& GET_CODE (next_insn) == JUMP_INSN)
{
rtx pattern = PATTERN (next_insn);
/* Is it a reversed fp conditional branch (eg uses add,tr) and
CCFP dies, then reverse our conditional and the branch to
avoid the add,tr. */
if (GET_CODE (pattern) == SET
&& SET_DEST (pattern) == pc_rtx
&& GET_CODE (SET_SRC (pattern)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC (pattern), 0)) == NE
&& GET_CODE (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == REG
&& REGNO (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == 0
&& GET_CODE (XEXP (SET_SRC (pattern), 1)) == PC
&& find_regno_note (next_insn, REG_DEAD, 0))
{
rtx tmp;
tmp = XEXP (SET_SRC (pattern), 1);
XEXP (SET_SRC (pattern), 1) = XEXP (SET_SRC (pattern), 2);
XEXP (SET_SRC (pattern), 2) = tmp;
INSN_CODE (next_insn) = -1;
return \"fcmp,sgl,%y2 %r0,%r1\";
}
}
return \"fcmp,sgl,%Y2 %r0,%r1\";
}"
[(set_attr "length" "4") [(set_attr "length" "4")
(set_attr "type" "fpcc")]) (set_attr "type" "fpcc")])
...@@ -396,7 +460,71 @@ ...@@ -396,7 +460,71 @@
[(match_operand:DF 0 "reg_or_0_operand" "fG") [(match_operand:DF 0 "reg_or_0_operand" "fG")
(match_operand:DF 1 "reg_or_0_operand" "fG")]))] (match_operand:DF 1 "reg_or_0_operand" "fG")]))]
"! TARGET_SOFT_FLOAT" "! TARGET_SOFT_FLOAT"
"fcmp,dbl,%Y2 %r0,%r1" "*
{
rtx next_insn;
/* See if this is later used in a reversed FP branch. If so, reverse our
condition and the branch. Doing so avoids a useless add,tr.
Don't do this if fcmp is in a delay slot since it's too much of a
headache to track down things on multiple paths. */
if (dbr_sequence_length ())
next_insn = NULL;
else
next_insn = NEXT_INSN (insn);
while (next_insn)
{
/* Jumps, calls and labels stop our search. */
if (GET_CODE (next_insn) == JUMP_INSN
|| GET_CODE (next_insn) == CALL_INSN
|| GET_CODE (next_insn) == CODE_LABEL)
break;
/* As does another fcmp insn. */
if (GET_CODE (next_insn) == INSN
&& GET_CODE (PATTERN (next_insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (next_insn))) == REG
&& REGNO (SET_DEST (PATTERN (next_insn))) == 0)
break;
if (GET_CODE (next_insn) == INSN
&& GET_CODE (PATTERN (next_insn)) == SEQUENCE)
next_insn = XVECEXP (PATTERN (next_insn), 0, 0);
else
next_insn = NEXT_INSN (next_insn);
}
/* Is NEXT_INSN a branch? */
if (next_insn
&& GET_CODE (next_insn) == JUMP_INSN)
{
rtx pattern = PATTERN (next_insn);
/* Is it a reversed fp conditional branch (eg uses add,tr) and
CCFP dies, then reverse our conditional and the branch to
avoid the add,tr. */
if (GET_CODE (pattern) == SET
&& SET_DEST (pattern) == pc_rtx
&& GET_CODE (SET_SRC (pattern)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC (pattern), 0)) == NE
&& GET_CODE (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == REG
&& REGNO (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == 0
&& GET_CODE (XEXP (SET_SRC (pattern), 1)) == PC
&& find_regno_note (next_insn, REG_DEAD, 0))
{
rtx tmp;
tmp = XEXP (SET_SRC (pattern), 1);
XEXP (SET_SRC (pattern), 1) = XEXP (SET_SRC (pattern), 2);
XEXP (SET_SRC (pattern), 2) = tmp;
INSN_CODE (next_insn) = -1;
return \"fcmp,dbl,%y2 %r0,%r1\";
}
}
return \"fcmp,dbl,%Y2 %r0,%r1\";
}"
[(set_attr "length" "4") [(set_attr "length" "4")
(set_attr "type" "fpcc")]) (set_attr "type" "fpcc")])
...@@ -761,6 +889,15 @@ ...@@ -761,6 +889,15 @@
comiclr,<< %2,%0,0\;ldi %2,%0" comiclr,<< %2,%0,0\;ldi %2,%0"
[(set_attr "type" "multi,multi") [(set_attr "type" "multi,multi")
(set_attr "length" "8,8")]) (set_attr "length" "8,8")])
(define_insn "abssi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(abs:SI (match_operand:SI 1 "register_operand" "0")))]
""
"comiclr,< 0,%0,0\;subi 0,%0,%0"
[(set_attr "type" "multi")
(set_attr "length" "8")])
;;; Experimental conditional move patterns ;;; Experimental conditional move patterns
(define_expand "movsicc" (define_expand "movsicc"
...@@ -1302,6 +1439,25 @@ ...@@ -1302,6 +1439,25 @@
[(set_attr "type" "load") [(set_attr "type" "load")
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r"))))]
"! TARGET_DISABLE_INDEXING"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"ldwx %2(0,%1),%0\";
else
return \"ldwx %1(0,%2),%0\";
}"
[(set_attr "type" "load")
(set_attr "length" "4")])
;; Load or store with base-register modification. ;; Load or store with base-register modification.
(define_insn "pre_ldwm" (define_insn "pre_ldwm"
...@@ -1624,6 +1780,25 @@ ...@@ -1624,6 +1780,25 @@
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_insn "" (define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(mem:HI (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r"))))]
"! TARGET_DISABLE_INDEXING"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"ldhx %2(0,%1),%0\";
else
return \"ldhx %1(0,%2),%0\";
}"
[(set_attr "type" "load")
(set_attr "length" "4")])
(define_insn ""
[(set (match_operand:HI 3 "register_operand" "=r") [(set (match_operand:HI 3 "register_operand" "=r")
(mem:HI (plus:SI (match_operand:SI 1 "register_operand" "0") (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "int5_operand" "L")))) (match_operand:SI 2 "int5_operand" "L"))))
...@@ -1690,6 +1865,25 @@ ...@@ -1690,6 +1865,25 @@
(set_attr "length" "4,4,4,4,4,4,4,4")]) (set_attr "length" "4,4,4,4,4,4,4,4")])
(define_insn "" (define_insn ""
[(set (match_operand:QI 0 "register_operand" "=r")
(mem:QI (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r"))))]
"! TARGET_DISABLE_INDEXING"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"ldbx %2(0,%1),%0\";
else
return \"ldbx %1(0,%2),%0\";
}"
[(set_attr "type" "load")
(set_attr "length" "4")])
(define_insn ""
[(set (match_operand:QI 3 "register_operand" "=r") [(set (match_operand:QI 3 "register_operand" "=r")
(mem:QI (plus:SI (match_operand:SI 1 "register_operand" "0") (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "0")
(match_operand:SI 2 "int5_operand" "L")))) (match_operand:SI 2 "int5_operand" "L"))))
...@@ -1727,19 +1921,55 @@ ...@@ -1727,19 +1921,55 @@
"" ""
" "
{ {
/* If the blocks are not at least word-aligned and rather big (>16 items), int size, align;
or the size is indeterminate, don't inline the copy code. A /* HP provides very fast block move library routine for the PA;
procedure call is better since it can check the alignment at this routine includes:
runtime and make the optimal decisions. */
if (INTVAL (operands[3]) < 4 4x4 byte at a time block moves,
&& (GET_CODE (operands[2]) != CONST_INT 1x4 byte at a time with alignment checked at runtime with
|| (INTVAL (operands[2]) / INTVAL (operands[3]) > 8))) attempts to align the source and destination as needed
FAIL; 1x1 byte loop
With that in mind, here's the heuristics to try and guess when
the inlined block move will be better than the library block
move:
If the size isn't constant, then always use the library routines.
If the size is large in respect to the known alignment, then use
the library routines.
If the size is small in repsect to the known alignment, then open
code the copy (since that will lead to better scheduling).
Else use the block move pattern. */
/* Undetermined size, use the library routine. */
if (GET_CODE (operands[2]) != CONST_INT)
FAIL;
size = INTVAL (operands[2]);
align = INTVAL (operands[3]);
align = align > 4 ? 4 : align;
/* If size/alignment > 8 (eg size is large in respect to alignment),
then use the library routines. */
if (size/align > 16)
FAIL;
/* This does happen, but not often enough to worry much about. */
if (size/align < MOVE_RATIO)
FAIL;
/* Fall through means we're going to use our block move pattern. */
operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
operands[4] = gen_reg_rtx (SImode); operands[4] = gen_reg_rtx (SImode);
operands[5] = gen_reg_rtx (SImode); operands[5] = gen_reg_rtx (SImode);
emit_insn (gen_movstrsi_internal (operands[0], operands[1], operands[4],
operands[5], operands[2], operands[3],
gen_reg_rtx (SImode)));
DONE;
}") }")
;; The operand constraints are written like this to support both compile-time ;; The operand constraints are written like this to support both compile-time
...@@ -1747,13 +1977,14 @@ ...@@ -1747,13 +1977,14 @@
;; the register with the byte count is clobbered by the copying code, and ;; the register with the byte count is clobbered by the copying code, and
;; therefore it is forced to operand 2. If the count is compile-time ;; therefore it is forced to operand 2. If the count is compile-time
;; determined, we need two scratch registers for the unrolled code. ;; determined, we need two scratch registers for the unrolled code.
(define_insn "" (define_insn "movstrsi_internal"
[(set (mem:BLK (match_operand:SI 0 "register_operand" "+r,r")) [(set (mem:BLK (match_operand:SI 0 "register_operand" "+r,r"))
(mem:BLK (match_operand:SI 1 "register_operand" "+r,r"))) (mem:BLK (match_operand:SI 1 "register_operand" "+r,r")))
(clobber (match_dup 0)) (clobber (match_dup 0))
(clobber (match_dup 1)) (clobber (match_dup 1))
(clobber (match_operand:SI 2 "register_operand" "=r,r")) ;loop cnt/tmp (clobber (match_operand:SI 2 "register_operand" "=r,r")) ;loop cnt/tmp
(clobber (match_operand:SI 3 "register_operand" "=&r,&r")) ;item tmp (clobber (match_operand:SI 3 "register_operand" "=&r,&r")) ;item tmp
(clobber (match_operand:SI 6 "register_operand" "=&r,&r")) ;item tmp2
(use (match_operand:SI 4 "arith_operand" "J,2")) ;byte count (use (match_operand:SI 4 "arith_operand" "J,2")) ;byte count
(use (match_operand:SI 5 "const_int_operand" "n,n"))] ;alignment (use (match_operand:SI 5 "const_int_operand" "n,n"))] ;alignment
"" ""
...@@ -1778,7 +2009,7 @@ ...@@ -1778,7 +2009,7 @@
&& operands[1] != CONST0_RTX (DFmode) && operands[1] != CONST0_RTX (DFmode)
&& ! TARGET_SOFT_FLOAT" && ! TARGET_SOFT_FLOAT"
"* return (which_alternative == 0 ? output_move_double (operands) "* return (which_alternative == 0 ? output_move_double (operands)
: \" fldds%F1 %1,%0\");" : \"fldds%F1 %1,%0\");"
[(set_attr "type" "move,fpload") [(set_attr "type" "move,fpload")
(set_attr "length" "16,4")]) (set_attr "length" "16,4")])
...@@ -1898,6 +2129,25 @@ ...@@ -1898,6 +2129,25 @@
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_insn "" (define_insn ""
[(set (match_operand:DF 0 "register_operand" "=fx")
(mem:DF (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r"))))]
"! TARGET_DISABLE_INDEXING && ! TARGET_SOFT_FLOAT"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"flddx %2(0,%1),%0\";
else
return \"flddx %1(0,%2),%0\";
}"
[(set_attr "type" "fpload")
(set_attr "length" "4")])
(define_insn ""
[(set (mem:DF (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") [(set (mem:DF (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
(const_int 8)) (const_int 8))
(match_operand:SI 2 "register_operand" "r"))) (match_operand:SI 2 "register_operand" "r")))
...@@ -1936,6 +2186,25 @@ ...@@ -1936,6 +2186,25 @@
[(set_attr "type" "fpstore") [(set_attr "type" "fpstore")
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_insn ""
[(set (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r")))
(match_operand:DF 0 "register_operand" "fx"))]
"! TARGET_DISABLE_INDEXING && ! TARGET_SOFT_FLOAT"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"fstdx %0,%2(0,%1)\";
else
return \"fstdx %0,%1(0,%2)\";
}"
[(set_attr "type" "fpstore")
(set_attr "length" "4")])
(define_expand "movdi" (define_expand "movdi"
[(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "") [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "")
(match_operand:DI 1 "general_operand" ""))] (match_operand:DI 1 "general_operand" ""))]
...@@ -2203,6 +2472,25 @@ ...@@ -2203,6 +2472,25 @@
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_insn "" (define_insn ""
[(set (match_operand:SF 0 "register_operand" "=fx")
(mem:SF (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r"))))]
"! TARGET_DISABLE_INDEXING && ! TARGET_SOFT_FLOAT"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"fldwx %2(0,%1),%0\";
else
return \"fldwx %1(0,%2),%0\";
}"
[(set_attr "type" "fpload")
(set_attr "length" "4")])
(define_insn ""
[(set (mem:SF (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r") [(set (mem:SF (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
(const_int 4)) (const_int 4))
(match_operand:SI 2 "register_operand" "r"))) (match_operand:SI 2 "register_operand" "r")))
...@@ -2240,7 +2528,27 @@ ...@@ -2240,7 +2528,27 @@
}" }"
[(set_attr "type" "fpstore") [(set_attr "type" "fpstore")
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_insn ""
[(set (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "basereg_operand" "r")))
(match_operand:SF 0 "register_operand" "fx"))]
"! TARGET_DISABLE_INDEXING && ! TARGET_SOFT_FLOAT"
"*
{
/* Reload can create backwards (relative to cse) unscaled index
address modes when eliminating registers and possibly for
pseudos that don't get hard registers. Deal with it. */
if (operands[1] == hard_frame_pointer_rtx
|| operands[1] == stack_pointer_rtx)
return \"fstwx %0,%2(0,%1)\";
else
return \"fstwx %0,%1(0,%2)\";
}"
[(set_attr "type" "fpstore")
(set_attr "length" "4")])
;;- zero extension instructions ;;- zero extension instructions
(define_insn "zero_extendhisi2" (define_insn "zero_extendhisi2"
......
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