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
This commit is contained in:
Jeff Law 1993-07-14 10:22:49 -06:00
parent 0a1daad47e
commit 2c4ff308b9
1 changed files with 117 additions and 12 deletions

View File

@ -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;
}