diff options
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc/config/sparc/sparc.c | 191 |
1 files changed, 102 insertions, 89 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 62be726..d45295f 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -2480,7 +2480,7 @@ output_move_quad (operands) int fix = offset - i * 4; /* Back up to the appropriate place. */ - temp[1] = gen_rtx_CONST_INT (VOIDmode, -fix); + temp[1] = GEN_INT (-fix); if (addreg0) { temp[0] = addreg0; @@ -2495,7 +2495,7 @@ output_move_quad (operands) wordpart[i]); /* Don't modify the register that's the destination of the move. */ - temp[0] = gen_rtx_CONST_INT (VOIDmode, -(offset - fix)); + temp[0] = GEN_INT (-(offset - fix)); if (addreg0 && REGNO (addreg0) != REGNO (wordpart[i][0])) { temp[1] = addreg0; @@ -2512,7 +2512,7 @@ output_move_quad (operands) } if (offset) { - temp[1] = gen_rtx_CONST_INT (VOIDmode, -offset); + temp[1] = GEN_INT (-offset); /* Undo the adds we just did. */ if (addreg0) { @@ -2712,6 +2712,17 @@ output_scc_insn (operands, insn) rtx label = 0, next = insn; int need_label = 0; + /* This code used to be called with final_sequence nonzero (for fpcc + delay slots), but that is no longer allowed. */ + if (final_sequence) + abort (); + + /* On UltraSPARC a conditional moves blocks until 3 cycles after prior loads + complete. It might be beneficial here to use branches if any recent + instructions were loads. */ + if (TARGET_V9 && REGNO (operands[1]) == SPARC_ICC_REG) + return "mov 0,%0\n\tmov%C2 %x1,1,%0"; + /* Try doing a jump optimization which jump.c can't do for us because we did not expose that setcc works by using branches. @@ -2724,21 +2735,12 @@ output_scc_insn (operands, insn) if (GET_CODE (next) == CODE_LABEL) label = next; next = NEXT_INSN (next); - if (next == 0) - break; } - while (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL); + while (next && GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL); - /* If we are in a sequence, and the following insn is a sequence also, - then just following the current insn's next field will take us to the - first insn of the next sequence, which is the wrong place. We don't - want to optimize with a branch that has had its delay slot filled. - Avoid this by verifying that NEXT_INSN (PREV_INSN (next)) == next - which fails only if NEXT is such a branch. */ - - if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next) - && (! final_sequence || NEXT_INSN (PREV_INSN (next)) == next)) + if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next)) label = JUMP_LABEL (next); + /* If not optimizing, jump label fields are not set. To be safe, always check here to whether label is still zero. */ if (label == 0) @@ -2752,35 +2754,8 @@ output_scc_insn (operands, insn) /* operands[3] is an unused slot. */ operands[3] = label; - /* If we are in a delay slot, assume it is the delay slot of an fpcc - insn since our type isn't allowed anywhere else. */ - - /* ??? Fpcc instructions no longer have delay slots, so this code is - probably obsolete. */ - - /* The fastest way to emit code for this is an annulled branch followed - by two move insns. This will take two cycles if the branch is taken, - and three cycles if the branch is not taken. - - However, if we are in the delay slot of another branch, this won't work, - because we can't put a branch in the delay slot of another branch. - The above sequence would effectively take 3 or 4 cycles respectively - since a no op would have be inserted between the two branches. - In this case, we want to emit a move, annulled branch, and then the - second move. This sequence always takes 3 cycles, and hence is faster - when we are in a branch delay slot. */ - - if (final_sequence) - { - strcpy (string, "mov 0,%0\n\t"); - strcat (string, output_cbranch (operands[2], 3, 0, 1, 0)); - strcat (string, "\n\tmov 1,%0"); - } - else - { - strcpy (string, output_cbranch (operands[2], 3, 0, 1, 0)); - strcat (string, "\n\tmov 1,%0\n\tmov 0,%0"); - } + strcpy (string, output_cbranch (operands[2], 3, 0, 1, 0)); + strcat (string, "\n\tmov 1,%0\n\tmov 0,%0"); if (need_label) strcat (string, "\n%l3:"); @@ -4380,13 +4355,16 @@ sparc_builtin_saveregs (arglist) ANNUL is non-zero if we should generate an annulling branch. - NOOP is non-zero if we have to follow this branch by a noop. */ + NOOP is non-zero if we have to follow this branch by a noop. + + INSN, if set, is the insn. */ char * -output_cbranch (op, label, reversed, annul, noop) +output_cbranch (op, label, reversed, annul, noop, insn) rtx op; int label; int reversed, annul, noop; + rtx insn; { static char string[20]; enum rtx_code code = GET_CODE (op); @@ -4506,8 +4484,6 @@ output_cbranch (op, label, reversed, annul, noop) if (annul) strcat (string, ",a"); - /* ??? If v9, optional prediction bit ",pt" or ",pf" goes here. */ - if (! TARGET_V9) { labeloff = 3; @@ -4515,6 +4491,11 @@ output_cbranch (op, label, reversed, annul, noop) } else { + rtx note; + + if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX))) + strcat (string, INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn"); + labeloff = 9; if (mode == CCFPmode || mode == CCFPEmode) { @@ -5372,34 +5353,49 @@ void sparc_initialize_trampoline (tramp, fnaddr, cxt) rtx tramp, fnaddr, cxt; { - rtx high_cxt = expand_shift (RSHIFT_EXPR, SImode, cxt, - size_int (10), 0, 1); - rtx high_fn = expand_shift (RSHIFT_EXPR, SImode, fnaddr, - size_int (10), 0, 1); - rtx low_cxt = expand_and (cxt, GEN_INT (0x3ff), 0); - rtx low_fn = expand_and (fnaddr, GEN_INT (0x3ff), 0); - rtx g1_sethi = gen_rtx_HIGH (SImode, GEN_INT (0x03000000)); - rtx g2_sethi = gen_rtx_HIGH (SImode, GEN_INT (0x05000000)); - rtx g1_ori = gen_rtx_HIGH (SImode, GEN_INT (0x82106000)); - rtx g2_ori = gen_rtx_HIGH (SImode, GEN_INT (0x8410A000)); - rtx tem = gen_reg_rtx (SImode); - emit_move_insn (tem, g1_sethi); - emit_insn (gen_iorsi3 (high_fn, high_fn, tem)); - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 0)), high_fn); - emit_move_insn (tem, g1_ori); - emit_insn (gen_iorsi3 (low_fn, low_fn, tem)); - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), low_fn); - emit_move_insn (tem, g2_sethi); - emit_insn (gen_iorsi3 (high_cxt, high_cxt, tem)); - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), high_cxt); - emit_move_insn (tem, g2_ori); - emit_insn (gen_iorsi3 (low_cxt, low_cxt, tem)); - emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 16)), low_cxt); + /* SPARC 32 bit trampoline: + + sethi %hi(fn),%g1 + sethi %hi(static),%g2 + jmp %g1+%lo(fn) + or %g2,%lo(static),%g2 + + SETHI i,r = 00rr rrr1 00ii iiii iiii iiii iiii iiii + JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii + */ + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 0)), + expand_binop (SImode, ior_optab, + expand_shift (RSHIFT_EXPR, SImode, fnaddr, + size_int (10), 0, 1), + GEN_INT (0x03000000), + NULL_RTX, 1, OPTAB_DIRECT)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), + expand_binop (SImode, ior_optab, + expand_shift (RSHIFT_EXPR, SImode, cxt, + size_int (10), 0, 1), + GEN_INT (0x05000000), + NULL_RTX, 1, OPTAB_DIRECT)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), + expand_binop (SImode, ior_optab, + expand_and (fnaddr, GEN_INT (0x3ff), NULL_RTX), + GEN_INT (0x81c06000), + NULL_RTX, 1, OPTAB_DIRECT)); + + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), + expand_binop (SImode, ior_optab, + expand_and (cxt, GEN_INT (0x3ff), NULL_RTX), + GEN_INT (0x8410a000), + NULL_RTX, 1, OPTAB_DIRECT)); + emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp)))); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, - plus_constant (tramp, 8))))); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, - plus_constant (tramp, 16))))); + /* On UltraSPARC a flush flushes an entire cache line. The trampoline is + aligned on a 16 byte boundary so one flush clears it all. */ + if (sparc_cpu != PROCESSOR_ULTRASPARC) + emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, + plus_constant (tramp, 8))))); } /* The 64 bit version is simpler because it makes more sense to load the @@ -5410,17 +5406,27 @@ void sparc64_initialize_trampoline (tramp, fnaddr, cxt) rtx tramp, fnaddr, cxt; { - emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), cxt); - emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 32)), fnaddr); + /* + rd %pc,%g1 + ldx [%g1+24],%g5 + jmp %g5 + ldx [%g1+16],%g5 + +16 bytes data + */ + + emit_move_insn (gen_rtx_MEM (SImode, tramp), + GEN_INT (0x83414000)); + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)), + GEN_INT (0xca586018)); + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)), + GEN_INT (0x81c04000)); + emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)), + GEN_INT (0xca586010)); + emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt); + emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 20)), fnaddr); emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, tramp)))); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, - plus_constant (tramp, 8))))); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, - plus_constant (tramp, 16))))); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, - plus_constant (tramp, 24))))); - emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, - plus_constant (tramp, 32))))); + if (sparc_cpu != PROCESSOR_ULTRASPARC) + emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8))))); } /* Subroutines to support a flat (single) register window calling @@ -6438,10 +6444,17 @@ sparc_v8plus_shift (operands, insn, opcode) if (GET_CODE (operands[3]) == SCRATCH) operands[3] = operands[0]; - output_asm_insn ("sllx %H1,32,%3", operands); - if (sparc_check_64 (operands[1], insn) <= 0) - output_asm_insn ("srl %L1,0,%L1", operands); - output_asm_insn ("or %L1,%3,%3", operands); + if (GET_CODE (operands[1]) == CONST_INT) + { + output_asm_insn ("mov %1,%3", operands); + } + else + { + output_asm_insn ("sllx %H1,32,%3", operands); + if (sparc_check_64 (operands[1], insn) <= 0) + output_asm_insn ("srl %L1,0,%L1", operands); + output_asm_insn ("or %L1,%3,%3", operands); + } strcpy(asm_code, opcode); if (which_alternative != 2) |