From 2c4ff308b9ddbf11cc47f4aec195c1f949fad377 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Wed, 14 Jul 1993 10:22:49 -0600 Subject: [PATCH] pa.c (output_call): New function to output a function call or millicode call... * pa.c (output_call): New function to output a function call or millicode call, possibly with a jump in the delay slot. (output_mul_insn): Accept additional argument, use output_call. (output_div_insn): Likewise. (output_mod_insn): Likewise. (jump_in_call_delay): New function to determine if the given JUMP_INSN is in the delay slot of a call or millicode call. From-SVN: r4915 --- gcc/config/pa/pa.c | 129 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 12 deletions(-) diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 9bbc3e270ba..f0da17ef9b8 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -2954,18 +2954,22 @@ import_milli (code) the proper registers. */ char * -output_mul_insn (unsignedp) +output_mul_insn (unsignedp, insn) int unsignedp; + rtx insn; { + if (unsignedp) { import_milli (mulU); - return "bl $$mulU,31%#"; + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulU"), + gen_rtx (REG, SImode, 31)); } else { import_milli (mulI); - return "bl $$mulI,31%#"; + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulI"), + gen_rtx (REG, SImode, 31)); } } @@ -3026,9 +3030,10 @@ emit_hpdiv_const (operands, unsignedp) } char * -output_div_insn (operands, unsignedp) +output_div_insn (operands, unsignedp, insn) rtx *operands; int unsignedp; + rtx insn; { int divisor; @@ -3036,18 +3041,28 @@ output_div_insn (operands, unsignedp) opcodes .*/ if (GET_CODE (operands[0]) == CONST_INT) { + static char buf[100]; divisor = INTVAL (operands[0]); if (!div_milli[divisor][unsignedp]) { + div_milli[divisor][unsignedp] = 1; if (unsignedp) output_asm_insn (".IMPORT $$divU_%0,MILLICODE", operands); else output_asm_insn (".IMPORT $$divI_%0,MILLICODE", operands); - div_milli[divisor][unsignedp] = 1; } if (unsignedp) - return "bl $$divU_%0,31%#"; - return "bl $$divI_%0,31%#"; + { + sprintf (buf, "$$divU_%d", INTVAL (operands[0])); + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf), + gen_rtx (REG, SImode, 31)); + } + else + { + sprintf (buf, "$$divI_%d", INTVAL (operands[0])); + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf), + gen_rtx (REG, SImode, 31)); + } } /* Divisor isn't a special constant. */ else @@ -3055,12 +3070,14 @@ output_div_insn (operands, unsignedp) if (unsignedp) { import_milli (divU); - return "bl $$divU,31%#"; + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divU"), + gen_rtx (REG, SImode, 31)); } else { import_milli (divI); - return "bl $$divI,31%#"; + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divI"), + gen_rtx (REG, SImode, 31)); } } } @@ -3068,18 +3085,21 @@ output_div_insn (operands, unsignedp) /* Output a $$rem millicode to do mod. */ char * -output_mod_insn (unsignedp) +output_mod_insn (unsignedp, insn) int unsignedp; + rtx insn; { if (unsignedp) { import_milli (remU); - return "bl $$remU,31%#"; + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remU"), + gen_rtx (REG, SImode, 31)); } else { import_milli (remI); - return "bl $$remI,31%#"; + return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remI"), + gen_rtx (REG, SImode, 31)); } } @@ -3650,6 +3670,68 @@ output_movb (operands, insn, which_alternative, reverse_comparison) } +/* INSN is either a function call or a millicode call. It may have an + unconditional jump in its delay slot. + + CALL_DEST is the routine we are calling. + + RETURN_POINTER is the register which will hold the return address. + %r2 for most calls, %r31 for millicode calls. */ +char * +output_call (insn, call_dest, return_pointer) + rtx insn; + rtx call_dest; + rtx return_pointer; + +{ + int distance; + rtx xoperands[4]; + rtx seq_insn; + + /* Handle common case -- empty delay slot or no jump in the delay slot. */ + if (dbr_sequence_length () == 0 + || (dbr_sequence_length () != 0 + && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)) + { + xoperands[0] = call_dest; + xoperands[1] = return_pointer; + output_asm_insn ("bl %0,%r1%#", xoperands); + return ""; + } + + /* This call has an unconditional jump in its delay slot. */ + + /* Use the containing sequence insn's address. */ + seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); + + distance = insn_addresses[INSN_UID (JUMP_LABEL (NEXT_INSN (insn)))] + - insn_addresses[INSN_UID (seq_insn)] - 8; + + /* If the branch was too far away, emit a normal call followed + by a nop, followed by the unconditional branch. + + If the branch is close, then adjust %r2 from within the + call's delay slot. */ + + xoperands[0] = call_dest; + xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1); + xoperands[2] = return_pointer; + if (! VAL_14_BITS_P (distance)) + output_asm_insn ("bl %0,%r2\n\tnop\n\tbl,n %1,%%r0", xoperands); + else + { + xoperands[3] = gen_label_rtx (); + output_asm_label (xoperands[3]); + output_asm_insn ("\n\tbl %0,%r2\n\tldo %1-%3-8(%r2),%r2", xoperands); + } + + /* Delete the jump. */ + PUT_CODE (NEXT_INSN (insn), NOTE); + NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0; + return ""; +} + extern struct obstack *saveable_obstack; /* In HPUX 8.0's shared library scheme, special relocations are needed @@ -3831,3 +3913,26 @@ movb_comparison_operator (op, mode) || GET_CODE (op) == LT || GET_CODE (op) == GE); } +/* Return 1 if INSN is in the delay slot of a call instruction. */ +int +jump_in_call_delay (insn) + rtx insn; +{ + + if (GET_CODE (insn) != JUMP_INSN) + return 0; + + if (PREV_INSN (insn) + && PREV_INSN (PREV_INSN (insn)) + && GET_CODE (next_active_insn (PREV_INSN (PREV_INSN (insn)))) == INSN) + { + rtx test_insn = next_active_insn (PREV_INSN (PREV_INSN (insn))); + + return (GET_CODE (PATTERN (test_insn)) == SEQUENCE + && XVECEXP (PATTERN (test_insn), 0, 1) == insn); + + } + else + return 0; +} + -- 2.30.2