aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>1993-07-14 10:22:49 -0600
committerJeff Law <law@gcc.gnu.org>1993-07-14 10:22:49 -0600
commit2c4ff308b9ddbf11cc47f4aec195c1f949fad377 (patch)
tree10514be42af8742a02822b942e3c02d3d0070cd3 /gcc
parent0a1daad47e3e349ec4910de45f7ff1d0c13c2d08 (diff)
downloadgcc-2c4ff308b9ddbf11cc47f4aec195c1f949fad377.zip
gcc-2c4ff308b9ddbf11cc47f4aec195c1f949fad377.tar.gz
gcc-2c4ff308b9ddbf11cc47f4aec195c1f949fad377.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/pa/pa.c129
1 files changed, 117 insertions, 12 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 9bbc3e2..f0da17e 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;
+}
+