diff options
author | rms <rms@138bc75d-0d04-0410-961f-82ee72b054a4> | 1992-03-22 02:54:46 +0000 |
---|---|---|
committer | rms <rms@138bc75d-0d04-0410-961f-82ee72b054a4> | 1992-03-22 02:54:46 +0000 |
commit | 94a720c880c2e986637c05eb7abc81dc8b0a67fc (patch) | |
tree | 6eb8d50d6e71783594855a7fe10a388984e7f809 /gcc/config/sparc/sparc.c | |
parent | 0a25608c2d55f69c2be6ef0595ce10936881916e (diff) | |
download | gcc-94a720c880c2e986637c05eb7abc81dc8b0a67fc.tar.gz |
*** empty log message ***
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@561 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc/config/sparc/sparc.c | 165 |
1 files changed, 76 insertions, 89 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index c2803ab757e..0979e8007b6 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -1059,16 +1059,13 @@ output_move_double (operands) op1 = operands[1], op2 = operands[0]; /* Now see if we can trust the address to be 8-byte aligned. */ - /* Trust global variables. */ + /* Trust double-precision floats in global variables. */ - if (GET_CODE (op2) == LO_SUM) + if (GET_CODE (XEXP (op2, 0)) == LO_SUM && GET_MODE (op2) == DFmode) { - operands[0] = op1; - operands[1] = op2; - if (final_sequence) abort (); - return "ldd %1,%0"; + return (op1 == operands[0] ? "ldd %1,%0" : "std %1,%0"); } if (GET_CODE (XEXP (op2, 0)) == PLUS) @@ -1102,12 +1099,12 @@ output_move_double (operands) && GET_MODE (operands[1]) == DFmode && (CONSTANT_P (XEXP (operands[1], 0)) /* Let user ask for it anyway. */ - || TARGET_ALIGN)) + || TARGET_HOPE_ALIGN)) return "ldd %1,%0"; else if (GET_CODE (operands[0]) == MEM && GET_MODE (operands[0]) == DFmode && (CONSTANT_P (XEXP (operands[0], 0)) - || TARGET_ALIGN)) + || TARGET_HOPE_ALIGN)) return "std %1,%0"; } @@ -1183,7 +1180,7 @@ output_fp_move_double (operands) addr = XEXP (operands[1], 0); /* Use ldd if known to be aligned. */ - if (TARGET_ALIGN + if (TARGET_HOPE_ALIGN || (GET_CODE (addr) == PLUS && (((XEXP (addr, 0) == frame_pointer_rtx || XEXP (addr, 0) == stack_pointer_rtx) @@ -1215,7 +1212,7 @@ output_fp_move_double (operands) addr = XEXP (operands[0], 0); /* Use std if we can be sure it is well-aligned. */ - if (TARGET_ALIGN + if (TARGET_HOPE_ALIGN || (GET_CODE (addr) == PLUS && (((XEXP (addr, 0) == frame_pointer_rtx || XEXP (addr, 0) == stack_pointer_rtx) @@ -1433,111 +1430,101 @@ output_block_move (operands) xoperands[1] = operands[1]; xoperands[2] = temp1; - /* We can't move more than this many bytes at a time - because we have only one register to move them through. */ - if (align > GET_MODE_SIZE (GET_MODE (temp1))) + /* We can't move more than this many bytes at a time because we have only + one register, %g1, to move them through. */ + if (align > UNITS_PER_WORD) { - align = GET_MODE_SIZE (GET_MODE (temp1)); - alignrtx = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (temp1))); + align = UNITS_PER_WORD; + alignrtx = gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD); } - /* If the size isn't known to be a multiple of the alignment, - we have to do it in smaller pieces. If we could determine that - the size was a multiple of 2 (or whatever), we could be smarter - about this. */ - if (GET_CODE (sizertx) != CONST_INT) - align = 1; - else + /* We consider 8 ld/st pairs, for a total of 16 inline insns to be + reasonable here. (Actually will emit a maximum of 18 inline insns for + the case of size == 31 and align == 4). */ + + if (GET_CODE (sizertx) == CONST_INT && (INTVAL (sizertx) / align) <= 8 + && memory_address_p (QImode, plus_constant_for_output (xoperands[0], + INTVAL (sizertx))) + && memory_address_p (QImode, plus_constant_for_output (xoperands[1], + INTVAL (sizertx)))) { int size = INTVAL (sizertx); - while (size % align) - align >>= 1; - } + int offset = 0; - if (align != INTVAL (alignrtx)) - alignrtx = gen_rtx (CONST_INT, VOIDmode, align); - - /* Recognize special cases of block moves. These occur - when GNU C++ is forced to treat something as BLKmode - to keep it in memory, when its mode could be represented - with something smaller. + /* We will store different integers into this particular RTX. */ + xoperands[2] = rtx_alloc (CONST_INT); + PUT_MODE (xoperands[2], VOIDmode); - We cannot do this for global variables, since we don't know - what pages they don't cross. Sigh. */ - if (GET_CODE (sizertx) == CONST_INT && INTVAL (sizertx) <= 16) - { - int size = INTVAL (sizertx); + /* This case is currently not handled. Abort instead of generating + bad code. */ + if (align > 4) + abort (); - if (align == 1) + if (align >= 4) { - if (memory_address_p (QImode, - plus_constant_for_output (xoperands[0], size)) - && memory_address_p (QImode, - plus_constant_for_output (xoperands[1], - size))) + for (i = (size >> 2) - 1; i >= 0; i--) { - /* We will store different integers into this particular RTX. */ - xoperands[2] = rtx_alloc (CONST_INT); - PUT_MODE (xoperands[2], VOIDmode); - for (i = size-1; i >= 0; i--) - { - INTVAL (xoperands[2]) = i; - output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", - xoperands); - } - return ""; + INTVAL (xoperands[2]) = (i << 2) + offset; + output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", + xoperands); } + offset += (size & ~0x3); + size = size & 0x3; + if (size == 0) + return ""; } - else if (align == 2) + + if (align >= 2) { - if (memory_address_p (HImode, - plus_constant_for_output (xoperands[0], size)) - && memory_address_p (HImode, - plus_constant_for_output (xoperands[1], - size))) + for (i = (size >> 1) - 1; i >= 0; i--) { - /* We will store different integers into this particular RTX. */ - xoperands[2] = rtx_alloc (CONST_INT); - PUT_MODE (xoperands[2], VOIDmode); - for (i = (size>>1)-1; i >= 0; i--) - { - INTVAL (xoperands[2]) = i<<1; - output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", - xoperands); - } - return ""; + INTVAL (xoperands[2]) = (i << 1) + offset; + output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", + xoperands); } + offset += (size & ~0x1); + size = size & 0x1; + if (size == 0) + return ""; } - else + + if (align >= 1) { - if (memory_address_p (SImode, - plus_constant_for_output (xoperands[0], size)) - && memory_address_p (SImode, - plus_constant_for_output (xoperands[1], - size))) + for (i = size - 1; i >= 0; i--) { - /* We will store different integers into this particular RTX. */ - xoperands[2] = rtx_alloc (CONST_INT); - PUT_MODE (xoperands[2], VOIDmode); - for (i = (size>>2)-1; i >= 0; i--) - { - INTVAL (xoperands[2]) = i<<2; - output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", - xoperands); - } - return ""; + INTVAL (xoperands[2]) = i + offset; + output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", + xoperands); } + return ""; } + + /* We should never reach here. */ + abort (); + } + + /* If the size isn't known to be a multiple of the alignment, + we have to do it in smaller pieces. If we could determine that + the size was a multiple of 2 (or whatever), we could be smarter + about this. */ + if (GET_CODE (sizertx) != CONST_INT) + align = 1; + else + { + int size = INTVAL (sizertx); + while (size % align) + align >>= 1; } + if (align != INTVAL (alignrtx)) + alignrtx = gen_rtx (CONST_INT, VOIDmode, align); + xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); xoperands[5] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); - /* This is the size of the transfer. - Either use the register which already contains the size, - or use a free register (used by no operands). - Also emit code to decrement the size value by ALIGN. */ + /* This is the size of the transfer. Emit code to decrement the size + value by ALIGN, and store the result in the temp1 register. */ output_size_for_block_move (sizertx, temp1, alignrtx); /* Must handle the case when the size is zero or negative, so the first thing |