--- gcc/config/sparc.c 2018/04/24 17:51:35 1.1.1.1 +++ gcc/config/sparc.c 2018/04/24 17:54:29 1.1.1.2 @@ -406,17 +406,6 @@ arith_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); } -/* Return truth value of whether OP can be used as an operand in a two - address arithmetic insn (such as set 123456,%o4) of mode MODE. */ - -int -arith32_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); -} - /* Return truth value of whether OP is a register or a CONST_DOUBLE. */ int @@ -620,7 +609,7 @@ legitimize_pic_address (orig, mode, reg, if (reg == 0) { - if (reload_in_progress) + if (reload_in_progress || reload_completed) abort (); else reg = gen_reg_rtx (Pmode); @@ -631,12 +620,23 @@ legitimize_pic_address (orig, mode, reg, /* If not during reload, allocate another temp reg here for loading in the address, so that these instructions can be optimized properly. */ - rtx temp_reg = (reload_in_progress ? reg : gen_reg_rtx (Pmode)); + rtx temp_reg = ((reload_in_progress || reload_completed) + ? reg : gen_reg_rtx (Pmode)); + /* Must put the SYMBOL_REF inside an UNSPEC here so that cse + won't get confused into thinking that these two instructions + are loading in the true address of the symbol. If in the + future a PIC rtx exists, that should be used instead. */ emit_insn (gen_rtx (SET, VOIDmode, temp_reg, - gen_rtx (HIGH, Pmode, orig))); + gen_rtx (HIGH, Pmode, + gen_rtx (UNSPEC, Pmode, + gen_rtvec (1, orig), + 0)))); emit_insn (gen_rtx (SET, VOIDmode, temp_reg, - gen_rtx (LO_SUM, Pmode, temp_reg, orig))); + gen_rtx (LO_SUM, Pmode, temp_reg, + gen_rtx (UNSPEC, Pmode, + gen_rtvec (1, orig), + 0)))); address = temp_reg; } else @@ -664,7 +664,7 @@ legitimize_pic_address (orig, mode, reg, if (reg == 0) { - if (reload_in_progress) + if (reload_in_progress || reload_completed) abort (); else reg = gen_reg_rtx (Pmode); @@ -684,7 +684,7 @@ legitimize_pic_address (orig, mode, reg, { if (SMALL_INT (offset)) return plus_constant_for_output (base, INTVAL (offset)); - else if (! reload_in_progress) + else if (! reload_in_progress && ! reload_completed) offset = force_reg (Pmode, offset); /* We can't create any new registers during reload, so use the SCRATCH reg provided by the reload_insi pattern. */ @@ -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,12 +1430,77 @@ 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 = UNITS_PER_WORD; + alignrtx = gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD); + } + + /* 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)))) { - align = GET_MODE_SIZE (GET_MODE (temp1)); - alignrtx = gen_rtx (CONST_INT, VOIDmode, GET_MODE_SIZE (GET_MODE (temp1))); + int size = INTVAL (sizertx); + int offset = 0; + + /* We will store different integers into this particular RTX. */ + xoperands[2] = rtx_alloc (CONST_INT); + PUT_MODE (xoperands[2], VOIDmode); + + /* This case is currently not handled. Abort instead of generating + bad code. */ + if (align > 4) + abort (); + + if (align >= 4) + { + for (i = (size >> 2) - 1; i >= 0; i--) + { + 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 ""; + } + + if (align >= 2) + { + for (i = (size >> 1) - 1; i >= 0; i--) + { + 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 ""; + } + + if (align >= 1) + { + for (i = size - 1; i >= 0; i--) + { + 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, @@ -1457,87 +1519,12 @@ output_block_move (operands) 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 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); - - if (align == 1) - { - if (memory_address_p (QImode, - plus_constant_for_output (xoperands[0], size)) - && memory_address_p (QImode, - plus_constant_for_output (xoperands[1], - size))) - { - /* 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 ""; - } - } - else 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))) - { - /* 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 ""; - } - } - else - { - if (memory_address_p (SImode, - plus_constant_for_output (xoperands[0], size)) - && memory_address_p (SImode, - plus_constant_for_output (xoperands[1], - size))) - { - /* 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 ""; - } - } - } - 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 @@ -1547,7 +1534,7 @@ output_block_move (operands) here. The SUN assembler complains about labels in branch delay slots, so we - do this before outputing the load address, so that there will always + do this before outputting the load address, so that there will always be a harmless insn between the branch here and the next label emitted below. */ @@ -2047,7 +2034,7 @@ output_cbranch (op, label, reversed, ann enum machine_mode mode = GET_MODE (XEXP (op, 0)); static char labelno[] = " %lX"; - /* ??? FP branches can not be preceeded by another floating point insn. + /* ??? FP branches can not be preceded by another floating point insn. Because there is currently no concept of pre-delay slots, we can fix this only by always emitting a nop before a floating point branch. */ @@ -2283,22 +2270,29 @@ output_arc_profiler (arcno, insert_after gen_rtx (PLUS, Pmode, profiler_label, gen_rtx (CONST_INT, VOIDmode, 4 * arcno))); register rtx profiler_reg = gen_reg_rtx (SImode); - register rtx temp = gen_reg_rtx (Pmode); - register rtx profiler_target = gen_rtx (MEM, SImode, - gen_rtx (LO_SUM, Pmode, temp, - profiler_target_addr)); - /* The insns are emitted from last to first after the insn insert_after. - Emit_insn_after is used because sometimes we want to put the - instrumentation code after the last insn of the function. */ - emit_insn_after (gen_rtx (SET, VOIDmode, profiler_target, profiler_reg), - insert_after); - emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, - gen_rtx (PLUS, SImode, profiler_reg, const1_rtx)), - insert_after); - emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, profiler_target), - insert_after); - emit_insn_after (gen_rtx (SET, VOIDmode, temp, - gen_rtx (HIGH, Pmode, profiler_target_addr)), + register rtx address_reg = gen_reg_rtx (Pmode); + rtx mem_ref; + + insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, address_reg, + gen_rtx (HIGH, Pmode, + profiler_target_addr)), + insert_after); + + mem_ref = gen_rtx (MEM, SImode, gen_rtx (LO_SUM, Pmode, address_reg, + profiler_target_addr)); + insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, + mem_ref), + insert_after); + + insert_after = emit_insn_after (gen_rtx (SET, VOIDmode, profiler_reg, + gen_rtx (PLUS, SImode, profiler_reg, + const1_rtx)), + insert_after); + + /* This is the same rtx as above, but it is not legal to share this rtx. */ + mem_ref = gen_rtx (MEM, SImode, gen_rtx (LO_SUM, Pmode, address_reg, + profiler_target_addr)); + emit_insn_after (gen_rtx (SET, VOIDmode, mem_ref, profiler_reg), insert_after); }