Commit 6a73009d by Jeff Law

pa.md (call expanders): For indirect calls, load %r22 with the function's address.

	* pa.md (call expanders): For indirect calls, load %r22 with the
	function's address.
	(indirect call patterns): No need to copy the call address into
	%r22 anymore.

	* pa.c (output_cbranch): Fix buglet in length handling of
	backwards branches with unfilled delay slots.
	(output_bb, output_bvb, output_dbra, output_movb): Likewise.

	* pa.md: Fix off-by-one error in length computations for all
	conditional branch patterns.

	* pa.h (output_bvb): Declare.
	* pa.c (output_bvb): New function to output branch on variable
	bit insns.
	* pa.md (branch-on-variable-bit): New patterns.

	* pa.h (TARGET_MILLICODE_LONG_CALLS): Delete swtich and all
	references.
	(output_millicode_call): Declare new function
	* pa.md (millicode calls): Update length computation to handle
	variable length millicode calls.
	(call pattners): Likewise.
	(indirect call patterns): Update length compuations and output
	templates to handle variable length millicode calls.
	(plabel_dereference): Likewise.
	* pa.c (override_options): Give warnings when incompatable
	options are used.
	(output_mul_insn): Call output_millicode_call instead of
	output_call, eliminate last argument to output_millicode_call.
	(output_div_insn): Likewise.
	(output_mod_insn): Likewise.
	(output_call): Rewrite long call code to handle variable length
	millicode calls.  Eliminate support for calling mul, div and mod
	millicode routines.
	(output_millicode_call): New function for calling mul, div and mod
	millicode routines.

From-SVN: r10610
parent 68944452
...@@ -97,6 +97,16 @@ override_options () ...@@ -97,6 +97,16 @@ override_options ()
{ {
warning ("Unknown -mschedule= option (%s).\nValid options are 700, 7100 and 7100LC\n", pa_cpu_string); warning ("Unknown -mschedule= option (%s).\nValid options are 700, 7100 and 7100LC\n", pa_cpu_string);
} }
if (flag_pic && TARGET_PORTABLE_RUNTIME)
{
warning ("PIC code generation is not supported in the portable runtime model\n");
}
if (flag_pic && TARGET_NO_SPACE_REGS)
{
warning ("PIC code generation is not compatable with fast indirect calls\n");
}
} }
...@@ -3166,8 +3176,7 @@ output_mul_insn (unsignedp, insn) ...@@ -3166,8 +3176,7 @@ output_mul_insn (unsignedp, insn)
rtx insn; rtx insn;
{ {
import_milli (mulI); import_milli (mulI);
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulI"), return output_millicode_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulI"));
gen_rtx (REG, SImode, 31));
} }
/* Emit the rtl for doing a division by a constant. */ /* Emit the rtl for doing a division by a constant. */
...@@ -3246,14 +3255,14 @@ output_div_insn (operands, unsignedp, insn) ...@@ -3246,14 +3255,14 @@ output_div_insn (operands, unsignedp, insn)
if (unsignedp) if (unsignedp)
{ {
sprintf (buf, "$$divU_%d", INTVAL (operands[0])); sprintf (buf, "$$divU_%d", INTVAL (operands[0]));
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf), return output_millicode_call (insn,
gen_rtx (REG, SImode, 31)); gen_rtx (SYMBOL_REF, SImode, buf));
} }
else else
{ {
sprintf (buf, "$$divI_%d", INTVAL (operands[0])); sprintf (buf, "$$divI_%d", INTVAL (operands[0]));
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf), return output_millicode_call (insn,
gen_rtx (REG, SImode, 31)); gen_rtx (SYMBOL_REF, SImode, buf));
} }
} }
/* Divisor isn't a special constant. */ /* Divisor isn't a special constant. */
...@@ -3262,14 +3271,14 @@ output_div_insn (operands, unsignedp, insn) ...@@ -3262,14 +3271,14 @@ output_div_insn (operands, unsignedp, insn)
if (unsignedp) if (unsignedp)
{ {
import_milli (divU); import_milli (divU);
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divU"), return output_millicode_call (insn,
gen_rtx (REG, SImode, 31)); gen_rtx (SYMBOL_REF, SImode, "$$divU"));
} }
else else
{ {
import_milli (divI); import_milli (divI);
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divI"), return output_millicode_call (insn,
gen_rtx (REG, SImode, 31)); gen_rtx (SYMBOL_REF, SImode, "$$divI"));
} }
} }
} }
...@@ -3284,14 +3293,14 @@ output_mod_insn (unsignedp, insn) ...@@ -3284,14 +3293,14 @@ output_mod_insn (unsignedp, insn)
if (unsignedp) if (unsignedp)
{ {
import_milli (remU); import_milli (remU);
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remU"), return output_millicode_call (insn,
gen_rtx (REG, SImode, 31)); gen_rtx (SYMBOL_REF, SImode, "$$remU"));
} }
else else
{ {
import_milli (remI); import_milli (remI);
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remI"), return output_millicode_call (insn,
gen_rtx (REG, SImode, 31)); gen_rtx (SYMBOL_REF, SImode, "$$remI"));
} }
} }
...@@ -3554,7 +3563,7 @@ output_cbranch (operands, nullify, length, negated, insn) ...@@ -3554,7 +3563,7 @@ output_cbranch (operands, nullify, length, negated, insn)
&& ! forward_branch_p (insn) && ! forward_branch_p (insn)
&& insn_addresses && insn_addresses
&& VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))] && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
- insn_addresses[INSN_UID (insn)])) - insn_addresses[INSN_UID (insn)] - 8))
{ {
strcpy (buf, "com%I2b,"); strcpy (buf, "com%I2b,");
if (negated) if (negated)
...@@ -3681,7 +3690,7 @@ output_bb (operands, nullify, length, negated, insn, which) ...@@ -3681,7 +3690,7 @@ output_bb (operands, nullify, length, negated, insn, which)
&& ! forward_branch_p (insn) && ! forward_branch_p (insn)
&& insn_addresses && insn_addresses
&& VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))] && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
- insn_addresses[INSN_UID (insn)])) - insn_addresses[INSN_UID (insn)] - 8))
{ {
strcpy (buf, "bb,"); strcpy (buf, "bb,");
if ((which == 0 && negated) if ((which == 0 && negated)
...@@ -3719,6 +3728,144 @@ output_bb (operands, nullify, length, negated, insn, which) ...@@ -3719,6 +3728,144 @@ output_bb (operands, nullify, length, negated, insn, which)
return buf; return buf;
} }
/* This routine handles all the branch-on-variable-bit conditional branch
sequences we might need to generate. It handles nullification of delay
slots, varying length branches, negated branches and all combinations
of the above. it returns the appropriate output template to emit the
branch. */
char *
output_bvb (operands, nullify, length, negated, insn, which)
rtx *operands;
int nullify, length, negated;
rtx insn;
int which;
{
static char buf[100];
int useskip = 0;
/* A conditional branch to the following instruction (eg the delay slot) is
asking for a disaster. I do not think this can happen as this pattern
is only used when optimizing; jump optimization should eliminate the
jump. But be prepared just in case. */
if (next_active_insn (JUMP_LABEL (insn)) == next_active_insn (insn))
return "";
/* If this is a long branch with its delay slot unfilled, set `nullify'
as it can nullify the delay slot and save a nop. */
if (length == 8 && dbr_sequence_length () == 0)
nullify = 1;
/* If this is a short forward conditional branch which did not get
its delay slot filled, the delay slot can still be nullified. */
if (! nullify && length == 4 && dbr_sequence_length () == 0)
nullify = forward_branch_p (insn);
/* A forward branch over a single nullified insn can be done with a
extrs instruction. This avoids a single cycle penalty due to
mis-predicted branch if we fall through (branch not taken). */
if (length == 4
&& next_real_insn (insn) != 0
&& get_attr_length (next_real_insn (insn)) == 4
&& JUMP_LABEL (insn) == next_nonnote_insn (next_real_insn (insn))
&& nullify)
useskip = 1;
switch (length)
{
/* All short conditional branches except backwards with an unfilled
delay slot. */
case 4:
if (useskip)
strcpy (buf, "vextrs,");
else
strcpy (buf, "bvb,");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, ">=");
else
strcat (buf, "<");
if (useskip)
strcat (buf, " %0,1,0");
else if (nullify && negated)
strcat (buf, ",n %0,%3");
else if (nullify && ! negated)
strcat (buf, ",n %0,%2");
else if (! nullify && negated)
strcat (buf, "%0,%3");
else if (! nullify && ! negated)
strcat (buf, " %0,%2");
break;
/* All long conditionals. Note an short backward branch with an
unfilled delay slot is treated just like a long backward branch
with an unfilled delay slot. */
case 8:
/* Handle weird backwards branch with a filled delay slot
with is nullified. */
if (dbr_sequence_length () != 0
&& ! forward_branch_p (insn)
&& nullify)
{
strcpy (buf, "bvb,");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, "<");
else
strcat (buf, ">=");
if (negated)
strcat (buf, ",n %0,.+12\n\tbl %3,0");
else
strcat (buf, ",n %0,.+12\n\tbl %2,0");
}
/* Handle short backwards branch with an unfilled delay slot.
Using a bb;nop rather than extrs;bl saves 1 cycle for both
taken and untaken branches. */
else if (dbr_sequence_length () == 0
&& ! forward_branch_p (insn)
&& insn_addresses
&& VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
- insn_addresses[INSN_UID (insn)] - 8))
{
strcpy (buf, "bvb,");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, ">=");
else
strcat (buf, "<");
if (negated)
strcat (buf, " %0,%3%#");
else
strcat (buf, " %0,%2%#");
}
else
{
strcpy (buf, "vextrs,");
if ((which == 0 && negated)
|| (which == 1 && ! negated))
strcat (buf, "<");
else
strcat (buf, ">=");
if (nullify && negated)
strcat (buf, " %0,1,0\n\tbl,n %3,0");
else if (nullify && ! negated)
strcat (buf, " %0,1,0\n\tbl,n %2,0");
else if (negated)
strcat (buf, " %0,1,0\n\tbl %3,0");
else
strcat (buf, " %0,1,0\n\tbl %2,0");
}
break;
default:
abort();
}
return buf;
}
/* Return the output template for emitting a dbra type insn. /* Return the output template for emitting a dbra type insn.
Note it may perform some output operations on its own before Note it may perform some output operations on its own before
...@@ -3786,7 +3933,7 @@ output_dbra (operands, insn, which_alternative) ...@@ -3786,7 +3933,7 @@ output_dbra (operands, insn, which_alternative)
&& ! forward_branch_p (insn) && ! forward_branch_p (insn)
&& insn_addresses && insn_addresses
&& VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))] && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
- insn_addresses[INSN_UID (insn)])) - insn_addresses[INSN_UID (insn)] - 8))
return "addib,%C2 %1,%0,%3%#"; return "addib,%C2 %1,%0,%3%#";
/* Handle normal cases. */ /* Handle normal cases. */
...@@ -3892,7 +4039,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison) ...@@ -3892,7 +4039,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
&& ! forward_branch_p (insn) && ! forward_branch_p (insn)
&& insn_addresses && insn_addresses
&& VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))] && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
- insn_addresses[INSN_UID (insn)])) - insn_addresses[INSN_UID (insn)] - 8))
return "movb,%C2 %1,%0,%3%#"; return "movb,%C2 %1,%0,%3%#";
/* Handle normal cases. */ /* Handle normal cases. */
if (nullify) if (nullify)
...@@ -3928,41 +4075,177 @@ output_movb (operands, insn, which_alternative, reverse_comparison) ...@@ -3928,41 +4075,177 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
} }
/* INSN is either a function call or a millicode call. It may have an /* INSN is a millicode call. It may have an unconditional jump in its delay
unconditional jump in its delay slot. slot.
CALL_DEST is the routine we are calling.
RETURN_POINTER is the register which will hold the return address. CALL_DEST is the routine we are calling. */
%r2 for most calls, %r31 for millicode calls.
When TARGET_MILLICODE_LONG_CALLS is true, then we have to assume
that two instruction sequences must be used to reach the millicode
routines (including dyncall!). */
char * char *
output_call (insn, call_dest, return_pointer) output_millicode_call (insn, call_dest)
rtx insn; rtx insn;
rtx call_dest; rtx call_dest;
rtx return_pointer;
{ {
int distance; int distance;
rtx xoperands[4]; rtx xoperands[4];
rtx seq_insn; rtx seq_insn;
/* Handle long millicode calls for mod, div, and mul. */ /* Handle common case -- empty delay slot or no jump in the delay slot,
if (TARGET_PORTABLE_RUNTIME and we're sure that the branch will reach the beginning of the $CODE$
|| (TARGET_MILLICODE_LONG_CALLS && REGNO (return_pointer) == 31)) subspace. */
if ((dbr_sequence_length () == 0
/* CYGNUS LOCAL mentor6480hack/law */
&& (get_attr_length (insn) == 8 || get_attr_length (insn) == 28))
/* END CYGNUS LOCAL */
|| (dbr_sequence_length () != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
&& get_attr_length (insn) == 4))
{ {
xoperands[0] = call_dest; xoperands[0] = call_dest;
xoperands[1] = return_pointer; output_asm_insn ("bl %0,%%r31%#", xoperands);
output_asm_insn ("ldil L%%%0,%%r29", xoperands);
output_asm_insn ("ldo R%%%0(%%r29),%%r29", xoperands);
output_asm_insn ("blr 0,%r1\n\tbv,n 0(%%r29)\n\tnop", xoperands);
return ""; return "";
} }
/* This call may not reach the beginning of the $CODE$ subspace. */
if (get_attr_length (insn) > 4)
{
int delay_insn_deleted = 0;
rtx xoperands[2];
rtx link;
/* We need to emit an inline long-call branch. */
if (dbr_sequence_length () != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
{
/* A non-jump insn in the delay slot. By definition we can
emit this insn before the call. */
final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0);
/* Now delete the delay insn. */
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
delay_insn_deleted = 1;
}
/* If we're allowed to use be/ble instructions, then this is the
best sequence to use for a long millicode call. */
if (TARGET_NO_SPACE_REGS
|| ! (flag_pic || TARGET_PORTABLE_RUNTIME))
{
xoperands[0] = call_dest;
output_asm_insn ("ldil L%%%0,%%r31", xoperands);
output_asm_insn ("ble R%%%0(%%sr4,%%r31)", xoperands);
output_asm_insn ("nop", xoperands);
}
/* Pure portable runtime doesn't allow be/ble; we also don't have
PIC support int he assembler/linker, so this sequence is needed. */
else if (TARGET_PORTABLE_RUNTIME)
{
xoperands[0] = call_dest;
/* Get the address of our target into %r29. */
output_asm_insn ("ldil L%%%0,%%r29", xoperands);
output_asm_insn ("ldo R%%%0(%%r29),%%r29", xoperands);
/* Get our return address into %r31. */
output_asm_insn ("blr 0,%%r31", xoperands);
/* Jump to our target address in %r29. */
output_asm_insn ("bv,n 0(%%r29)", xoperands);
/* Empty delay slot. Note this insn gets fetched twice and
executed once. To be safe we use a nop. */
output_asm_insn ("nop", xoperands);
return "";
}
/* PIC long millicode call sequence. */
else
{
xoperands[0] = call_dest;
xoperands[1] = gen_label_rtx ();
/* Get our address + 8 into %r1. */
output_asm_insn ("bl .+8,%%r1", xoperands);
/* Add %r1 to the offset of our target from the next insn. */
output_asm_insn ("addil L%%%0-%1,%%r1", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R%%%0-%1(%%r1),%%r1", xoperands);
/* Get the return address into %r31. */
output_asm_insn ("blr 0,%%r31", xoperands);
/* Branch to our target which is in %r1. */
output_asm_insn ("bv,n 0(%%r1)", xoperands);
/* Empty delay slot. Note this insn gets fetched twice and
executed once. To be safe we use a nop. */
output_asm_insn ("nop", xoperands);
}
/* If we had a jump in the call's delay slot, output it now. */
if (dbr_sequence_length () != 0
&& !delay_insn_deleted)
{
xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
output_asm_insn ("b,n %0", xoperands);
/* Now delete the delay insn. */
PUT_CODE (NEXT_INSN (insn), NOTE);
NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
}
return "";
}
/* This call has an unconditional jump in its delay slot and the
call is known to reach its target or the beginning of the current
subspace. */
/* 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);
if (! VAL_14_BITS_P (distance))
output_asm_insn ("bl %0,%%r31\n\tnop\n\tbl,n %1,%%r0", xoperands);
else
{
xoperands[3] = gen_label_rtx ();
output_asm_insn ("\n\tbl %0,%%r31\n\tldo %1-%3(%%r31),%%r31", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[3]));
}
/* 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 "";
}
/* INSN is either a function call. It may have an unconditional jump
in its delay slot.
CALL_DEST is the routine we are calling. */
char *
output_call (insn, call_dest)
rtx insn;
rtx call_dest;
{
int distance;
rtx xoperands[4];
rtx seq_insn;
/* Handle common case -- empty delay slot or no jump in the delay slot, /* Handle common case -- empty delay slot or no jump in the delay slot,
and we're sure that the branch will reach the beginning of the $CODE$ and we're sure that the branch will reach the beginning of the $CODE$
subspace. */ subspace. */
...@@ -3973,8 +4256,7 @@ output_call (insn, call_dest, return_pointer) ...@@ -3973,8 +4256,7 @@ output_call (insn, call_dest, return_pointer)
&& get_attr_length (insn) == 4)) && get_attr_length (insn) == 4))
{ {
xoperands[0] = call_dest; xoperands[0] = call_dest;
xoperands[1] = return_pointer; output_asm_insn ("bl %0,%%r2%#", xoperands);
output_asm_insn ("bl %0,%r1%#", xoperands);
return ""; return "";
} }
...@@ -3990,13 +4272,14 @@ output_call (insn, call_dest, return_pointer) ...@@ -3990,13 +4272,14 @@ output_call (insn, call_dest, return_pointer)
function call well after the parameters have been set up, we function call well after the parameters have been set up, we
need to make sure any FP args appear in both the integer need to make sure any FP args appear in both the integer
and FP registers. Also, we need move any delay slot insn and FP registers. Also, we need move any delay slot insn
out of the delay slot -- Yuk! */ out of the delay slot. And finally, we can't rely on the linker
being able to fix the call to $$dyncall! -- Yuk!. */
if (dbr_sequence_length () != 0 if (dbr_sequence_length () != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN) && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
{ {
/* A non-jump insn in the delay slot. By definition we can /* A non-jump insn in the delay slot. By definition we can
emit this insn before the call (and in fact before argument emit this insn before the call (and in fact before argument
relocating. */ relocating. */
final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0); final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0);
/* Now delete the delay insn. */ /* Now delete the delay insn. */
...@@ -4042,6 +4325,8 @@ output_call (insn, call_dest, return_pointer) ...@@ -4042,6 +4325,8 @@ output_call (insn, call_dest, return_pointer)
} }
} }
/* Don't have to worry about TARGET_PORTABLE_RUNTIME here since
we don't have any direct calls in that case. */
if (flag_pic) if (flag_pic)
{ {
/* We have to load the address of the function using a procedure /* We have to load the address of the function using a procedure
...@@ -4050,8 +4335,9 @@ output_call (insn, call_dest, return_pointer) ...@@ -4050,8 +4335,9 @@ output_call (insn, call_dest, return_pointer)
have to defer outputting it of course... Not pretty. */ have to defer outputting it of course... Not pretty. */
xoperands[0] = gen_label_rtx (); xoperands[0] = gen_label_rtx ();
output_asm_insn ("addil LT%%%0,%%r19\n\tldw RT%%%0(%%r1),%%r22", xoperands[1] = gen_label_rtx ();
xoperands); output_asm_insn ("addil LT%%%0,%%r19", xoperands);
output_asm_insn ("ldw RT%%%0(%%r1),%%r22", xoperands);
output_asm_insn ("ldw 0(0,%%r22),%%r22", xoperands); output_asm_insn ("ldw 0(0,%%r22),%%r22", xoperands);
if (deferred_plabels == 0) if (deferred_plabels == 0)
...@@ -4064,25 +4350,42 @@ output_call (insn, call_dest, return_pointer) ...@@ -4064,25 +4350,42 @@ output_call (insn, call_dest, return_pointer)
deferred_plabels[n_deferred_plabels].internal_label = xoperands[0]; deferred_plabels[n_deferred_plabels].internal_label = xoperands[0];
deferred_plabels[n_deferred_plabels].symbol = call_dest; deferred_plabels[n_deferred_plabels].symbol = call_dest;
n_deferred_plabels++; n_deferred_plabels++;
/* Get our address + 8 into %r1. */
output_asm_insn ("bl .+8,%%r1", xoperands);
/* Add %r1 to the offset of dyncall from the next insn. */
output_asm_insn ("addil L%%$$dyncall-%1,%%r1", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R%%$$dyncall-%1(%%r1),%%r1", xoperands);
/* Get the return address into %r31. */
output_asm_insn ("blr 0,%%r31", xoperands);
/* Branch to our target which is in %r1. */
output_asm_insn ("bv 0(%%r1)", xoperands);
/* Copy the return address into %r2 also. */
output_asm_insn ("copy %%r31,%%r2", xoperands);
} }
else else
{ {
/* Now emit the inline long-call. */ /* No PIC stuff to worry about. We can use ldil;ble. */
xoperands[0] = call_dest; xoperands[0] = call_dest;
output_asm_insn ("ldil LP%%%0,%%r22\n\tldo RP%%%0(%%r22),%%r22",
xoperands);
}
/* If TARGET_MILLICODE_LONG_CALLS, then we must use a long-call sequence /* Get the address of our target into %r22. */
to call dyncall! */ output_asm_insn ("ldil LP%%%0,%%r22", xoperands);
if (TARGET_MILLICODE_LONG_CALLS) output_asm_insn ("ldo RP%%%0(%%r22),%%r22", xoperands);
{
output_asm_insn ("ldil L%%$$dyncall,%%r31", xoperands); /* Get the high part of the address of $dyncall into %r2, then
output_asm_insn ("ldo R%%$$dyncall(%%r31),%%r31", xoperands); add in the low part in the branch instruction. */
output_asm_insn ("blr 0,%%r2\n\tbv,n 0(%%r31)\n\tnop", xoperands); output_asm_insn ("ldil L%%$$dyncall,%%r2", xoperands);
output_asm_insn ("ble R%%$$dyncall(%%sr4,%%r2)", xoperands);
/* Copy the return pointer into both %r31 and %r2. */
output_asm_insn ("copy %%r31,%%r2", xoperands);
} }
else
output_asm_insn ("bl $$dyncall,%%r31\n\tcopy %%r31,%%r2", xoperands);
/* If we had a jump in the call's delay slot, output it now. */ /* If we had a jump in the call's delay slot, output it now. */
if (dbr_sequence_length () != 0 if (dbr_sequence_length () != 0
...@@ -4099,7 +4402,9 @@ output_call (insn, call_dest, return_pointer) ...@@ -4099,7 +4402,9 @@ output_call (insn, call_dest, return_pointer)
return ""; return "";
} }
/* This call has an unconditional jump in its delay slot. */ /* This call has an unconditional jump in its delay slot and the
call is known to reach its target or the beginning of the current
subspace. */
/* Use the containing sequence insn's address. */ /* Use the containing sequence insn's address. */
seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0))); seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
...@@ -4115,13 +4420,12 @@ output_call (insn, call_dest, return_pointer) ...@@ -4115,13 +4420,12 @@ output_call (insn, call_dest, return_pointer)
xoperands[0] = call_dest; xoperands[0] = call_dest;
xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1); xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
xoperands[2] = return_pointer;
if (! VAL_14_BITS_P (distance)) if (! VAL_14_BITS_P (distance))
output_asm_insn ("bl %0,%r2\n\tnop\n\tbl,n %1,%%r0", xoperands); output_asm_insn ("bl %0,%%r2\n\tnop\n\tbl,n %1,%%r0", xoperands);
else else
{ {
xoperands[3] = gen_label_rtx (); xoperands[3] = gen_label_rtx ();
output_asm_insn ("\n\tbl %0,%r2\n\tldo %1-%3(%r2),%r2", xoperands); output_asm_insn ("\n\tbl %0,%%r2\n\tldo %1-%3(%%r2),%%r2", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[3])); CODE_LABEL_NUMBER (xoperands[3]));
} }
......
...@@ -70,25 +70,14 @@ extern int target_flags; ...@@ -70,25 +70,14 @@ extern int target_flags;
never cross a space boundary. Such assumptions are generally safe for never cross a space boundary. Such assumptions are generally safe for
building kernels and statically linked executables. Code compiled with building kernels and statically linked executables. Code compiled with
this option will fail miserably if the executable is dynamically linked this option will fail miserably if the executable is dynamically linked
or uses nested functions! */ or uses nested functions!
#define TARGET_FAST_INDIRECT_CALLS (target_flags & 4)
This is also used to trigger agressive unscaled index addressing. */
#define TARGET_NO_SPACE_REGS (target_flags & 4)
/* Allow unconditional jumps in the delay slots of call instructions. */ /* Allow unconditional jumps in the delay slots of call instructions. */
#define TARGET_JUMP_IN_DELAY (target_flags & 8) #define TARGET_JUMP_IN_DELAY (target_flags & 8)
/* In rare cases, a millicode call via "bl" can not be turned into
a millicode call using "ble" (when SHLIB_INFO subspace is very large).
This option forces just millicode calls to use inline long-calls
This is far more efficient than the old long-call option which forced
every function to be called indirectly (as is still the case for
TARGET_PORTABLE_RUNTIME).
??? What about simple jumps, they can suffer from the same problem.
Would require significant surgery in pa.md. */
#define TARGET_MILLICODE_LONG_CALLS (target_flags & 16)
/* Disable indexed addressing modes. */ /* Disable indexed addressing modes. */
#define TARGET_DISABLE_INDEXING (target_flags & 32) #define TARGET_DISABLE_INDEXING (target_flags & 32)
...@@ -125,16 +114,14 @@ extern int target_flags; ...@@ -125,16 +114,14 @@ extern int target_flags;
{"pa-risc-1-1", 1}, \ {"pa-risc-1-1", 1}, \
{"disable-fpregs", 2}, \ {"disable-fpregs", 2}, \
{"no-disable-fpregs", -2}, \ {"no-disable-fpregs", -2}, \
{"fast-indirect-calls", 4}, \ {"no-space-regs", 4}, \
{"no-fast-indirect-calls", -4},\ {"space-regs", -4},\
{"jump-in-delay", 8}, \ {"jump-in-delay", 8}, \
{"no-jump-in-delay", -8}, \ {"no-jump-in-delay", -8}, \
{"millicode-long-calls", 16},\
{"no-millicode-long-calls", -16},\
{"disable-indexing", 32}, \ {"disable-indexing", 32}, \
{"no-disable-indexing", -32},\ {"no-disable-indexing", -32},\
{"portable-runtime", 64+16},\ {"portable-runtime", 64}, \
{"no-portable-runtime", -(64+16)},\ {"no-portable-runtime", -64},\
{"gas", 128}, \ {"gas", 128}, \
{"no-gas", -128}, \ {"no-gas", -128}, \
{"soft-float", 256}, \ {"soft-float", 256}, \
......
...@@ -1154,7 +1154,7 @@ ...@@ -1154,7 +1154,7 @@
[(set_attr "type" "cbranch") [(set_attr "type" "cbranch")
(set (attr "length") (set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)))]) (const_int 8)))])
...@@ -1177,7 +1177,7 @@ ...@@ -1177,7 +1177,7 @@
[(set_attr "type" "cbranch") [(set_attr "type" "cbranch")
(set (attr "length") (set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)))]) (const_int 8)))])
...@@ -1200,7 +1200,7 @@ ...@@ -1200,7 +1200,7 @@
[(set_attr "type" "cbranch") [(set_attr "type" "cbranch")
(set (attr "length") (set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)))]) (const_int 8)))])
...@@ -1222,7 +1222,7 @@ ...@@ -1222,7 +1222,7 @@
[(set_attr "type" "cbranch") [(set_attr "type" "cbranch")
(set (attr "length") (set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)))]) (const_int 8)))])
...@@ -1244,7 +1244,7 @@ ...@@ -1244,7 +1244,7 @@
[(set_attr "type" "cbranch") [(set_attr "type" "cbranch")
(set (attr "length") (set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)))]) (const_int 8)))])
...@@ -1266,7 +1266,96 @@ ...@@ -1266,7 +1266,96 @@
[(set_attr "type" "cbranch") [(set_attr "type" "cbranch")
(set (attr "length") (set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4)
(const_int 8)))])
;; Branch on Variable Bit patterns.
(define_insn ""
[(set (pc)
(if_then_else
(ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "register_operand" "q"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"*
{
return output_bvb (operands, INSN_ANNULLED_BRANCH_P (insn),
get_attr_length (insn), 0, insn, 0);
}"
[(set_attr "type" "cbranch")
(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8184))
(const_int 4)
(const_int 8)))])
(define_insn ""
[(set (pc)
(if_then_else
(ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "register_operand" "q"))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))]
""
"*
{
return output_bvb (operands, INSN_ANNULLED_BRANCH_P (insn),
get_attr_length (insn), 1, insn, 0);
}"
[(set_attr "type" "cbranch")
(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8184))
(const_int 4)
(const_int 8)))])
(define_insn ""
[(set (pc)
(if_then_else
(eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "register_operand" "q"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
"*
{
return output_bvb (operands, INSN_ANNULLED_BRANCH_P (insn),
get_attr_length (insn), 0, insn, 1);
}"
[(set_attr "type" "cbranch")
(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8184))
(const_int 4)
(const_int 8)))])
(define_insn ""
[(set (pc)
(if_then_else
(eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "register_operand" "q"))
(const_int 0))
(pc)
(label_ref (match_operand 2 "" ""))))]
""
"*
{
return output_bvb (operands, INSN_ANNULLED_BRANCH_P (insn),
get_attr_length (insn), 1, insn, 1);
}"
[(set_attr "type" "cbranch")
(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
(const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)))]) (const_int 8)))])
...@@ -2943,12 +3032,29 @@ ...@@ -2943,12 +3032,29 @@
"* return output_mul_insn (0, insn);" "* return output_mul_insn (0, insn);"
[(set_attr "type" "milli") [(set_attr "type" "milli")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; Target (or stub) within reach
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 0))) (const_int 240000))
(const_int 4) (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 24)))]) (const_int 0)))
(const_int 4)
;; NO_SPACE_REGS
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
;; same as NO_SPACE_REGS code
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 8)]
;; Out of range and either PIC or PORTABLE_RUNTIME
(const_int 24)))])
;;; Division and mod. ;;; Division and mod.
(define_expand "divsi3" (define_expand "divsi3"
...@@ -2980,12 +3086,29 @@ ...@@ -2980,12 +3086,29 @@
return output_div_insn (operands, 0, insn);" return output_div_insn (operands, 0, insn);"
[(set_attr "type" "milli") [(set_attr "type" "milli")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; Target (or stub) within reach
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 0))) (const_int 240000))
(const_int 4) (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 24)))]) (const_int 0)))
(const_int 4)
;; NO_SPACE_REGS
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
;; same as NO_SPACE_REGS code
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 8)]
;; Out of range and either PIC or PORTABLE_RUNTIME
(const_int 24)))])
(define_expand "udivsi3" (define_expand "udivsi3"
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" "")) [(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
...@@ -3016,12 +3139,29 @@ ...@@ -3016,12 +3139,29 @@
return output_div_insn (operands, 1, insn);" return output_div_insn (operands, 1, insn);"
[(set_attr "type" "milli") [(set_attr "type" "milli")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; Target (or stub) within reach
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 0))) (const_int 240000))
(const_int 4) (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 24)))]) (const_int 0)))
(const_int 4)
;; NO_SPACE_REGS
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
;; same as NO_SPACE_REGS code
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 8)]
;; Out of range and either PIC or PORTABLE_RUNTIME
(const_int 24)))])
(define_expand "modsi3" (define_expand "modsi3"
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" "")) [(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
...@@ -3049,12 +3189,29 @@ ...@@ -3049,12 +3189,29 @@
return output_mod_insn (0, insn);" return output_mod_insn (0, insn);"
[(set_attr "type" "milli") [(set_attr "type" "milli")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; Target (or stub) within reach
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 0))) (const_int 240000))
(const_int 4) (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 24)))]) (const_int 0)))
(const_int 4)
;; NO_SPACE_REGS
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
;; same as NO_SPACE_REGS code
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 8)]
;; Out of range and either PIC or PORTABLE_RUNTIME
(const_int 24)))])
(define_expand "umodsi3" (define_expand "umodsi3"
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" "")) [(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
...@@ -3082,12 +3239,29 @@ ...@@ -3082,12 +3239,29 @@
return output_mod_insn (1, insn);" return output_mod_insn (1, insn);"
[(set_attr "type" "milli") [(set_attr "type" "milli")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; Target (or stub) within reach
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 0))) (const_int 240000))
(const_int 4) (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 24)))]) (const_int 0)))
(const_int 4)
;; NO_SPACE_REGS
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
;; same as NO_SPACE_REGS code
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 8)]
;; Out of range and either PIC or PORTABLE_RUNTIME
(const_int 24)))])
;;- and instructions ;;- and instructions
;; We define DImode `and` so with DImode `not` we can get ;; We define DImode `and` so with DImode `not` we can get
...@@ -3738,7 +3912,7 @@ ...@@ -3738,7 +3912,7 @@
;; on whether or not we can add the proper offset to %r2 with an ldo ;; on whether or not we can add the proper offset to %r2 with an ldo
;; instruction. ;; instruction.
(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4)] (const_int 4)]
(const_int 8)))]) (const_int 8)))])
...@@ -3832,8 +4006,11 @@ ...@@ -3832,8 +4006,11 @@
if (GET_CODE (op) == SYMBOL_REF) if (GET_CODE (op) == SYMBOL_REF)
call_insn = emit_call_insn (gen_call_internal_symref (op, operands[1])); call_insn = emit_call_insn (gen_call_internal_symref (op, operands[1]));
else else
call_insn = emit_call_insn (gen_call_internal_reg (force_reg (SImode, op), {
operands[1])); rtx tmpreg = gen_rtx (REG, SImode, 22);
emit_move_insn (tmpreg, force_reg (SImode, op));
call_insn = emit_call_insn (gen_call_internal_reg (operands[1]));
}
if (flag_pic) if (flag_pic)
{ {
...@@ -3847,6 +4024,16 @@ ...@@ -3847,6 +4024,16 @@
emit_move_insn (pic_offset_table_rtx, emit_move_insn (pic_offset_table_rtx,
gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM_SAVED)); gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM_SAVED));
emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
/* Gross. We have to keep the scheduler from moving the restore
of the PIC register away from the call. SCHED_GROUP_P is
supposed to do this, but for some reason the compiler will
go into an infinite loop when we use that.
This method (blockage insn) may make worse code (then again
it may not since calls are nearly blockages anyway), but at
least it should work. */
emit_insn (gen_blockage ());
} }
DONE; DONE;
}") }")
...@@ -3864,39 +4051,91 @@ ...@@ -3864,39 +4051,91 @@
}" }"
[(set_attr "type" "call") [(set_attr "type" "call")
(set (attr "length") (set (attr "length")
;; If we're sure that we can either reach the target or that the
;; linker can use a long-branch stub, then the length is 4 bytes.
;;
;; For long-calls the length will be either 52 bytes (non-pic)
;; or 68 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc)) (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000)) (const_int 240000))
(const_int 4) (const_int 4)
(if_then_else (ne (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (if_then_else (eq (symbol_ref "flag_pic")
(const_int 0)) (const_int 0))
(const_int 64) (const_int 52)
(const_int 52))))]) (const_int 68))))])
(define_insn "call_internal_reg" (define_insn "call_internal_reg"
[(call (mem:SI (match_operand:SI 0 "register_operand" "r")) [(call (mem:SI (reg:SI 22))
(match_operand 1 "" "i")) (match_operand 0 "" "i"))
(clobber (reg:SI 2)) (clobber (reg:SI 2))
(use (const_int 1))] (use (const_int 1))]
"" ""
"* "*
{ {
if (TARGET_FAST_INDIRECT_CALLS) rtx xoperands[2];
return \"ble 0(%%sr4,%r0)\;copy %%r31,%%r2\";
/* Yuk! bl may not be able to reach $$dyncall. */ /* First the special case for kernels, level 0 systems, etc. */
if (TARGET_PORTABLE_RUNTIME || TARGET_MILLICODE_LONG_CALLS) if (TARGET_NO_SPACE_REGS)
return \"copy %r0,%%r22\;ldil L%%$$dyncall,%%r31\;ldo R%%$$dyncall(%%r31),%%r31\;blr 0,%%r2\;bv,n 0(%%r31)\;nop\"; return \"ble 0(%%sr4,%%r22)\;copy %%r31,%%r2\";
else
return \"copy %r0,%%r22\;.CALL\\tARGW0=GR\;bl $$dyncall,%%r31\;copy %%r31,%%r2\"; /* Now the normal case -- we can reach $$dyncall directly or
we're sure that we can get there via a long-branch stub.
No need to check target flags as the length uniquely identifies
the remaining cases. */
if (get_attr_length (insn) == 8)
return \".CALL\\tARGW0=GR\;bl $$dyncall,%%r31\;copy %%r31,%%r2\";
/* Long millicode call, but we are not generating PIC or portable runtime
code. */
if (get_attr_length (insn) == 12)
return \"CALL\\tARGW0=GR\;ldil L%%$$dyncall,%%r2\;ble R%%$$dyncall(%%sr4,%%r2)\;copy %%r31,%%r2\";
/* Long millicode call for portable runtime. */
if (get_attr_length (insn) == 20)
return \"ldil L%%$$dyncall,%%r31\;ldo R%%$$dyncall(%%r31),%%r31\;blr 0,%%r2\;bv,n 0(%%r31)\;nop\";
/* If we're generating PIC code. */
xoperands[0] = operands[0];
xoperands[1] = gen_label_rtx ();
output_asm_insn (\"bl .+8,%%r1\", xoperands);
output_asm_insn (\"addil L%%$$dyncall-%1,%%r1\", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn (\"ldo R%%$$dyncall-%1(%%r1),%%r1\", xoperands);
output_asm_insn (\"blr 0,%%r2\", xoperands);
output_asm_insn (\"bv,n 0(%%r1)\\n\\tnop\", xoperands);
return \"\";
}" }"
[(set_attr "type" "dyncall") [(set_attr "type" "dyncall")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; First NO_SPACE_REGS
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))) (const_int 0))
(const_int 12) (const_int 8)
(const_int 24)))])
;; Target (or stub) within reach
(and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
(eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0)))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 12)
(ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(const_int 20)]
;; Out of range PIC case
(const_int 24)))])
(define_expand "call_value" (define_expand "call_value"
[(parallel [(set (match_operand 0 "" "") [(parallel [(set (match_operand 0 "" "")
...@@ -3924,10 +4163,12 @@ ...@@ -3924,10 +4163,12 @@
op, op,
operands[2])); operands[2]));
else else
call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0], {
force_reg (SImode, op), rtx tmpreg = gen_rtx (REG, SImode, 22);
operands[2])); emit_move_insn (tmpreg, force_reg (SImode, op));
call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
operands[2]));
}
if (flag_pic) if (flag_pic)
{ {
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx); use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
...@@ -3950,16 +4191,6 @@ ...@@ -3950,16 +4191,6 @@
it may not since calls are nearly blockages anyway), but at it may not since calls are nearly blockages anyway), but at
least it should work. */ least it should work. */
emit_insn (gen_blockage ()); emit_insn (gen_blockage ());
/* Gross. We have to keep the scheduler from moving the restore
of the PIC register away from the call. SCHED_GROUP_P is
supposed to do this, but for some reason the compiler will
go into an infinite loop when we use that.
This method (blockage insn) may make worse code (then again
it may not since calls are nearly blockages anyway), but at
least it should work. */
emit_insn (gen_blockage ());
} }
DONE; DONE;
}") }")
...@@ -3979,40 +4210,92 @@ ...@@ -3979,40 +4210,92 @@
}" }"
[(set_attr "type" "call") [(set_attr "type" "call")
(set (attr "length") (set (attr "length")
;; If we're sure that we can either reach the target or that the
;; linker can use a long-branch stub, then the length is 4 bytes.
;;
;; For long-calls the length will be either 52 bytes (non-pic)
;; or 68 bytes (pic). */
;; Else we have to use a long-call;
(if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc)) (if_then_else (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000)) (const_int 240000))
(const_int 4) (const_int 4)
(if_then_else (ne (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (if_then_else (eq (symbol_ref "flag_pic")
(const_int 0)) (const_int 0))
(const_int 64) (const_int 52)
(const_int 52))))]) (const_int 68))))])
(define_insn "call_value_internal_reg" (define_insn "call_value_internal_reg"
[(set (match_operand 0 "" "=rf") [(set (match_operand 0 "" "=rf")
(call (mem:SI (match_operand:SI 1 "register_operand" "r")) (call (mem:SI (reg:SI 22))
(match_operand 2 "" "i"))) (match_operand 1 "" "i")))
(clobber (reg:SI 2)) (clobber (reg:SI 2))
(use (const_int 1))] (use (const_int 1))]
"" ""
"* "*
{ {
if (TARGET_FAST_INDIRECT_CALLS) rtx xoperands[2];
return \"ble 0(%%sr4,%r1)\;copy %%r31,%%r2\";
/* First the special case for kernels, level 0 systems, etc. */
/* Yuk! bl may not be able to reach $$dyncall. */ if (TARGET_NO_SPACE_REGS)
if (TARGET_PORTABLE_RUNTIME || TARGET_MILLICODE_LONG_CALLS) return \"ble 0(%%sr4,%%r22)\;copy %%r31,%%r2\";
return \"copy %r1,%%r22\;ldil L%%$$dyncall,%%r31\;ldo R%%$$dyncall(%%r31),%%r31\;blr 0,%%r2\;bv,n 0(%%r31)\;nop\";
else /* Now the normal case -- we can reach $$dyncall directly or
return \"copy %r1,%%r22\;.CALL\\tARGW0=GR\;bl $$dyncall,%%r31\;copy %%r31,%%r2\"; we're sure that we can get there via a long-branch stub.
No need to check target flags as the length uniquely identifies
the remaining cases. */
if (get_attr_length (insn) == 8)
return \".CALL\\tARGW0=GR\;bl $$dyncall,%%r31\;copy %%r31,%%r2\";
/* Long millicode call, but we are not generating PIC or portable runtime
code. */
if (get_attr_length (insn) == 12)
return \".CALL\\tARGW0=GR\;ldil L%%$$dyncall,%%r2\;ble R%%$$dyncall(%%sr4,%%r2)\;copy %%r31,%%r2\";
/* Long millicode call for portable runtime. */
if (get_attr_length (insn) == 20)
return \"ldil L%%$$dyncall,%%r31\;ldo R%%$$dyncall(%%r31),%%r31\;blr 0,%%r2\;bv,n 0(%%r31)\;nop\";
/* If we're generating PIC code. */
xoperands[0] = operands[1];
xoperands[1] = gen_label_rtx ();
output_asm_insn (\"bl .+8,%%r1\", xoperands);
output_asm_insn (\"addil L%%$$dyncall-%1,%%r1\", xoperands);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn (\"ldo R%%$$dyncall-%1(%%r1),%%r1\", xoperands);
output_asm_insn (\"blr 0,%%r2\", xoperands);
output_asm_insn (\"bv,n 0(%%r1)\\n\\tnop\", xoperands);
return \"\";
}" }"
[(set_attr "type" "dyncall") [(set_attr "type" "dyncall")
(set (attr "length") (set (attr "length")
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (cond [
(const_int 0)) ;; First NO_SPACE_REGS
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS") (ne (symbol_ref "TARGET_NO_SPACE_REGS")
(const_int 0))) (const_int 0))
(const_int 12) (const_int 8)
(const_int 24)))])
;; Target (or stub) within reach
(and (lt (plus (symbol_ref "total_code_bytes") (pc))
(const_int 240000))
(eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0)))
(const_int 8)
;; Out of reach, but not PIC or PORTABLE_RUNTIME
(and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(eq (symbol_ref "flag_pic")
(const_int 0)))
(const_int 12)
(ne (symbol_ref "TARGET_PORTABLE_RUNTIME")
(const_int 0))
(const_int 20)]
;; Out of range PIC case
(const_int 24)))])
;; Call subroutine returning any type. ;; Call subroutine returning any type.
...@@ -4153,7 +4436,7 @@ ...@@ -4153,7 +4436,7 @@
;; Short branch has length of 4 ;; Short branch has length of 4
;; Long branch has length of 8 ;; Long branch has length of 8
(if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)) (const_int 8))
...@@ -4163,12 +4446,12 @@ ...@@ -4163,12 +4446,12 @@
(if_then_else (lt (match_dup 3) (pc)) (if_then_else (lt (match_dup 3) (pc))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 24)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 24))))
(const_int 8188)) (const_int 8184))
(const_int 24) (const_int 24)
(const_int 28)) (const_int 28))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 24) (const_int 24)
(const_int 28))) (const_int 28)))
;; Loop counter in memory case. ;; Loop counter in memory case.
...@@ -4176,12 +4459,12 @@ ...@@ -4176,12 +4459,12 @@
(if_then_else (lt (match_dup 3) (pc)) (if_then_else (lt (match_dup 3) (pc))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16)) (const_int 16))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16))))))]) (const_int 16))))))])
...@@ -4209,7 +4492,7 @@ ...@@ -4209,7 +4492,7 @@
;; Short branch has length of 4 ;; Short branch has length of 4
;; Long branch has length of 8 ;; Long branch has length of 8
(if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)) (const_int 8))
...@@ -4219,12 +4502,12 @@ ...@@ -4219,12 +4502,12 @@
(if_then_else (lt (match_dup 3) (pc)) (if_then_else (lt (match_dup 3) (pc))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 24)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 24))))
(const_int 8188)) (const_int 8184))
(const_int 24) (const_int 24)
(const_int 28)) (const_int 28))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 24) (const_int 24)
(const_int 28))) (const_int 28)))
;; Loop counter in memory case. ;; Loop counter in memory case.
...@@ -4232,12 +4515,12 @@ ...@@ -4232,12 +4515,12 @@
(if_then_else (lt (match_dup 3) (pc)) (if_then_else (lt (match_dup 3) (pc))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16)) (const_int 16))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16))))))]) (const_int 16))))))])
...@@ -4260,7 +4543,7 @@ ...@@ -4260,7 +4543,7 @@
;; Short branch has length of 4 ;; Short branch has length of 4
;; Long branch has length of 8 ;; Long branch has length of 8
(if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)) (const_int 8))
...@@ -4270,19 +4553,19 @@ ...@@ -4270,19 +4553,19 @@
(if_then_else (lt (match_dup 3) (pc)) (if_then_else (lt (match_dup 3) (pc))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16)) (const_int 16))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16))) (const_int 16)))
;; Loop counter in memory case. ;; Loop counter in memory case.
;; Extra goo to deal with additional reload insns. ;; Extra goo to deal with additional reload insns.
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 8) (const_int 8)
(const_int 12)))))]) (const_int 12)))))])
...@@ -4306,7 +4589,7 @@ ...@@ -4306,7 +4589,7 @@
;; Short branch has length of 4 ;; Short branch has length of 4
;; Long branch has length of 8 ;; Long branch has length of 8
(if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (if_then_else (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 4) (const_int 4)
(const_int 8)) (const_int 8))
...@@ -4316,19 +4599,19 @@ ...@@ -4316,19 +4599,19 @@
(if_then_else (lt (match_dup 3) (pc)) (if_then_else (lt (match_dup 3) (pc))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16)) (const_int 16))
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 12) (const_int 12)
(const_int 16))) (const_int 16)))
;; Loop counter in memory case. ;; Loop counter in memory case.
;; Extra goo to deal with additional reload insns. ;; Extra goo to deal with additional reload insns.
(if_then_else (if_then_else
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8)))) (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
(const_int 8188)) (const_int 8184))
(const_int 8) (const_int 8)
(const_int 12)))))]) (const_int 12)))))])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment