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
This commit is contained in:
parent
68944452e4
commit
6a73009d9d
|
@ -97,6 +97,16 @@ override_options ()
|
|||
{
|
||||
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)
|
|||
rtx insn;
|
||||
{
|
||||
import_milli (mulI);
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulI"),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$mulI"));
|
||||
}
|
||||
|
||||
/* Emit the rtl for doing a division by a constant. */
|
||||
|
@ -3246,14 +3255,14 @@ output_div_insn (operands, unsignedp, insn)
|
|||
if (unsignedp)
|
||||
{
|
||||
sprintf (buf, "$$divU_%d", INTVAL (operands[0]));
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn,
|
||||
gen_rtx (SYMBOL_REF, SImode, buf));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (buf, "$$divI_%d", INTVAL (operands[0]));
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, buf),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn,
|
||||
gen_rtx (SYMBOL_REF, SImode, buf));
|
||||
}
|
||||
}
|
||||
/* Divisor isn't a special constant. */
|
||||
|
@ -3262,14 +3271,14 @@ output_div_insn (operands, unsignedp, insn)
|
|||
if (unsignedp)
|
||||
{
|
||||
import_milli (divU);
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divU"),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn,
|
||||
gen_rtx (SYMBOL_REF, SImode, "$$divU"));
|
||||
}
|
||||
else
|
||||
{
|
||||
import_milli (divI);
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$divI"),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn,
|
||||
gen_rtx (SYMBOL_REF, SImode, "$$divI"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3284,14 +3293,14 @@ output_mod_insn (unsignedp, insn)
|
|||
if (unsignedp)
|
||||
{
|
||||
import_milli (remU);
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remU"),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn,
|
||||
gen_rtx (SYMBOL_REF, SImode, "$$remU"));
|
||||
}
|
||||
else
|
||||
{
|
||||
import_milli (remI);
|
||||
return output_call (insn, gen_rtx (SYMBOL_REF, SImode, "$$remI"),
|
||||
gen_rtx (REG, SImode, 31));
|
||||
return output_millicode_call (insn,
|
||||
gen_rtx (SYMBOL_REF, SImode, "$$remI"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3554,7 +3563,7 @@ output_cbranch (operands, nullify, length, negated, insn)
|
|||
&& ! forward_branch_p (insn)
|
||||
&& insn_addresses
|
||||
&& 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,");
|
||||
if (negated)
|
||||
|
@ -3681,7 +3690,7 @@ output_bb (operands, nullify, length, negated, insn, which)
|
|||
&& ! forward_branch_p (insn)
|
||||
&& insn_addresses
|
||||
&& 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,");
|
||||
if ((which == 0 && negated)
|
||||
|
@ -3719,6 +3728,144 @@ output_bb (operands, nullify, length, negated, insn, which)
|
|||
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.
|
||||
|
||||
Note it may perform some output operations on its own before
|
||||
|
@ -3786,7 +3933,7 @@ output_dbra (operands, insn, which_alternative)
|
|||
&& ! forward_branch_p (insn)
|
||||
&& insn_addresses
|
||||
&& 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%#";
|
||||
|
||||
/* Handle normal cases. */
|
||||
|
@ -3892,7 +4039,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
|
|||
&& ! forward_branch_p (insn)
|
||||
&& insn_addresses
|
||||
&& 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%#";
|
||||
/* Handle normal cases. */
|
||||
if (nullify)
|
||||
|
@ -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
|
||||
unconditional jump in its delay slot.
|
||||
/* INSN is 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.
|
||||
|
||||
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!). */
|
||||
CALL_DEST is the routine we are calling. */
|
||||
|
||||
char *
|
||||
output_call (insn, call_dest, return_pointer)
|
||||
output_millicode_call (insn, call_dest)
|
||||
rtx insn;
|
||||
rtx call_dest;
|
||||
rtx return_pointer;
|
||||
|
||||
{
|
||||
int distance;
|
||||
rtx xoperands[4];
|
||||
rtx seq_insn;
|
||||
|
||||
/* Handle long millicode calls for mod, div, and mul. */
|
||||
if (TARGET_PORTABLE_RUNTIME
|
||||
|| (TARGET_MILLICODE_LONG_CALLS && REGNO (return_pointer) == 31))
|
||||
/* 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$
|
||||
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[1] = return_pointer;
|
||||
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);
|
||||
output_asm_insn ("bl %0,%%r31%#", xoperands);
|
||||
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,
|
||||
and we're sure that the branch will reach the beginning of the $CODE$
|
||||
subspace. */
|
||||
|
@ -3973,8 +4256,7 @@ output_call (insn, call_dest, return_pointer)
|
|||
&& get_attr_length (insn) == 4))
|
||||
{
|
||||
xoperands[0] = call_dest;
|
||||
xoperands[1] = return_pointer;
|
||||
output_asm_insn ("bl %0,%r1%#", xoperands);
|
||||
output_asm_insn ("bl %0,%%r2%#", xoperands);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -3990,13 +4272,14 @@ output_call (insn, call_dest, return_pointer)
|
|||
function call well after the parameters have been set up, we
|
||||
need to make sure any FP args appear in both the integer
|
||||
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
|
||||
&& 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 (and in fact before argument
|
||||
relocating. */
|
||||
emit this insn before the call (and in fact before argument
|
||||
relocating. */
|
||||
final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0);
|
||||
|
||||
/* Now delete the delay insn. */
|
||||
|
@ -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)
|
||||
{
|
||||
/* We have to load the address of the function using a procedure
|
||||
|
@ -4050,8 +4335,9 @@ output_call (insn, call_dest, return_pointer)
|
|||
have to defer outputting it of course... Not pretty. */
|
||||
|
||||
xoperands[0] = gen_label_rtx ();
|
||||
output_asm_insn ("addil LT%%%0,%%r19\n\tldw RT%%%0(%%r1),%%r22",
|
||||
xoperands);
|
||||
xoperands[1] = gen_label_rtx ();
|
||||
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);
|
||||
|
||||
if (deferred_plabels == 0)
|
||||
|
@ -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].symbol = call_dest;
|
||||
n_deferred_plabels++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now emit the inline long-call. */
|
||||
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
|
||||
to call dyncall! */
|
||||
if (TARGET_MILLICODE_LONG_CALLS)
|
||||
{
|
||||
output_asm_insn ("ldil L%%$$dyncall,%%r31", xoperands);
|
||||
output_asm_insn ("ldo R%%$$dyncall(%%r31),%%r31", xoperands);
|
||||
output_asm_insn ("blr 0,%%r2\n\tbv,n 0(%%r31)\n\tnop", xoperands);
|
||||
/* 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
|
||||
output_asm_insn ("bl $$dyncall,%%r31\n\tcopy %%r31,%%r2", xoperands);
|
||||
{
|
||||
/* No PIC stuff to worry about. We can use ldil;ble. */
|
||||
xoperands[0] = call_dest;
|
||||
|
||||
/* Get the address of our target into %r22. */
|
||||
output_asm_insn ("ldil LP%%%0,%%r22", xoperands);
|
||||
output_asm_insn ("ldo RP%%%0(%%r22),%%r22", xoperands);
|
||||
|
||||
/* Get the high part of the address of $dyncall into %r2, then
|
||||
add in the low part in the branch instruction. */
|
||||
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);
|
||||
}
|
||||
|
||||
/* If we had a jump in the call's delay slot, output it now. */
|
||||
if (dbr_sequence_length () != 0
|
||||
|
@ -4099,7 +4402,9 @@ output_call (insn, call_dest, return_pointer)
|
|||
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. */
|
||||
seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
|
||||
|
@ -4115,13 +4420,12 @@ output_call (insn, call_dest, return_pointer)
|
|||
|
||||
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);
|
||||
output_asm_insn ("bl %0,%%r2\n\tnop\n\tbl,n %1,%%r0", xoperands);
|
||||
else
|
||||
{
|
||||
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",
|
||||
CODE_LABEL_NUMBER (xoperands[3]));
|
||||
}
|
||||
|
|
|
@ -70,25 +70,14 @@ extern int target_flags;
|
|||
never cross a space boundary. Such assumptions are generally safe for
|
||||
building kernels and statically linked executables. Code compiled with
|
||||
this option will fail miserably if the executable is dynamically linked
|
||||
or uses nested functions! */
|
||||
#define TARGET_FAST_INDIRECT_CALLS (target_flags & 4)
|
||||
or uses nested functions!
|
||||
|
||||
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. */
|
||||
#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. */
|
||||
|
||||
#define TARGET_DISABLE_INDEXING (target_flags & 32)
|
||||
|
@ -125,16 +114,14 @@ extern int target_flags;
|
|||
{"pa-risc-1-1", 1}, \
|
||||
{"disable-fpregs", 2}, \
|
||||
{"no-disable-fpregs", -2}, \
|
||||
{"fast-indirect-calls", 4}, \
|
||||
{"no-fast-indirect-calls", -4},\
|
||||
{"no-space-regs", 4}, \
|
||||
{"space-regs", -4},\
|
||||
{"jump-in-delay", 8}, \
|
||||
{"no-jump-in-delay", -8}, \
|
||||
{"millicode-long-calls", 16},\
|
||||
{"no-millicode-long-calls", -16},\
|
||||
{"disable-indexing", 32}, \
|
||||
{"no-disable-indexing", -32},\
|
||||
{"portable-runtime", 64+16},\
|
||||
{"no-portable-runtime", -(64+16)},\
|
||||
{"portable-runtime", 64}, \
|
||||
{"no-portable-runtime", -64},\
|
||||
{"gas", 128}, \
|
||||
{"no-gas", -128}, \
|
||||
{"soft-float", 256}, \
|
||||
|
|
|
@ -1154,7 +1154,7 @@
|
|||
[(set_attr "type" "cbranch")
|
||||
(set (attr "length")
|
||||
(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 8)))])
|
||||
|
||||
|
@ -1177,7 +1177,7 @@
|
|||
[(set_attr "type" "cbranch")
|
||||
(set (attr "length")
|
||||
(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 8)))])
|
||||
|
||||
|
@ -1200,7 +1200,7 @@
|
|||
[(set_attr "type" "cbranch")
|
||||
(set (attr "length")
|
||||
(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)))])
|
||||
|
||||
|
@ -1222,7 +1222,7 @@
|
|||
[(set_attr "type" "cbranch")
|
||||
(set (attr "length")
|
||||
(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)))])
|
||||
|
||||
|
@ -1244,7 +1244,7 @@
|
|||
[(set_attr "type" "cbranch")
|
||||
(set (attr "length")
|
||||
(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)))])
|
||||
|
||||
|
@ -1266,7 +1266,96 @@
|
|||
[(set_attr "type" "cbranch")
|
||||
(set (attr "length")
|
||||
(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 8)))])
|
||||
|
||||
|
@ -2943,12 +3032,29 @@
|
|||
"* return output_mul_insn (0, insn);"
|
||||
[(set_attr "type" "milli")
|
||||
(set (attr "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 4)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; 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 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.
|
||||
(define_expand "divsi3"
|
||||
|
@ -2980,12 +3086,29 @@
|
|||
return output_div_insn (operands, 0, insn);"
|
||||
[(set_attr "type" "milli")
|
||||
(set (attr "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 4)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; 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 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"
|
||||
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
|
||||
|
@ -3016,12 +3139,29 @@
|
|||
return output_div_insn (operands, 1, insn);"
|
||||
[(set_attr "type" "milli")
|
||||
(set (attr "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 4)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; 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 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"
|
||||
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
|
||||
|
@ -3049,12 +3189,29 @@
|
|||
return output_mod_insn (0, insn);"
|
||||
[(set_attr "type" "milli")
|
||||
(set (attr "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 4)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; 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 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"
|
||||
[(set (reg:SI 26) (match_operand:SI 1 "move_operand" ""))
|
||||
|
@ -3082,12 +3239,29 @@
|
|||
return output_mod_insn (1, insn);"
|
||||
[(set_attr "type" "milli")
|
||||
(set (attr "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 4)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; 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 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
|
||||
;; We define DImode `and` so with DImode `not` we can get
|
||||
|
@ -3738,7 +3912,7 @@
|
|||
;; on whether or not we can add the proper offset to %r2 with an ldo
|
||||
;; instruction.
|
||||
(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 4)]
|
||||
(const_int 8)))])
|
||||
|
||||
|
@ -3832,8 +4006,11 @@
|
|||
if (GET_CODE (op) == SYMBOL_REF)
|
||||
call_insn = emit_call_insn (gen_call_internal_symref (op, operands[1]));
|
||||
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)
|
||||
{
|
||||
|
@ -3847,6 +4024,16 @@
|
|||
emit_move_insn (pic_offset_table_rtx,
|
||||
gen_rtx (REG, SImode, PIC_OFFSET_TABLE_REGNUM_SAVED));
|
||||
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;
|
||||
}")
|
||||
|
@ -3864,39 +4051,91 @@
|
|||
}"
|
||||
[(set_attr "type" "call")
|
||||
(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))
|
||||
(const_int 240000))
|
||||
(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 64)
|
||||
(const_int 52))))])
|
||||
(const_int 52)
|
||||
(const_int 68))))])
|
||||
|
||||
(define_insn "call_internal_reg"
|
||||
[(call (mem:SI (match_operand:SI 0 "register_operand" "r"))
|
||||
(match_operand 1 "" "i"))
|
||||
[(call (mem:SI (reg:SI 22))
|
||||
(match_operand 0 "" "i"))
|
||||
(clobber (reg:SI 2))
|
||||
(use (const_int 1))]
|
||||
""
|
||||
"*
|
||||
{
|
||||
if (TARGET_FAST_INDIRECT_CALLS)
|
||||
return \"ble 0(%%sr4,%r0)\;copy %%r31,%%r2\";
|
||||
rtx xoperands[2];
|
||||
|
||||
/* Yuk! bl may not be able to reach $$dyncall. */
|
||||
if (TARGET_PORTABLE_RUNTIME || TARGET_MILLICODE_LONG_CALLS)
|
||||
return \"copy %r0,%%r22\;ldil L%%$$dyncall,%%r31\;ldo R%%$$dyncall(%%r31),%%r31\;blr 0,%%r2\;bv,n 0(%%r31)\;nop\";
|
||||
else
|
||||
return \"copy %r0,%%r22\;.CALL\\tARGW0=GR\;bl $$dyncall,%%r31\;copy %%r31,%%r2\";
|
||||
/* First the special case for kernels, level 0 systems, etc. */
|
||||
if (TARGET_NO_SPACE_REGS)
|
||||
return \"ble 0(%%sr4,%%r22)\;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 "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 12)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; First NO_SPACE_REGS
|
||||
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
|
||||
(const_int 0))
|
||||
(const_int 8)
|
||||
|
||||
;; 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"
|
||||
[(parallel [(set (match_operand 0 "" "")
|
||||
|
@ -3924,10 +4163,12 @@
|
|||
op,
|
||||
operands[2]));
|
||||
else
|
||||
call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
|
||||
force_reg (SImode, op),
|
||||
operands[2]));
|
||||
|
||||
{
|
||||
rtx tmpreg = gen_rtx (REG, SImode, 22);
|
||||
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)
|
||||
{
|
||||
use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
|
||||
|
@ -3950,16 +4191,6 @@
|
|||
it may not since calls are nearly blockages anyway), but at
|
||||
least it should work. */
|
||||
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;
|
||||
}")
|
||||
|
@ -3979,40 +4210,92 @@
|
|||
}"
|
||||
[(set_attr "type" "call")
|
||||
(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))
|
||||
(const_int 240000))
|
||||
(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 64)
|
||||
(const_int 52))))])
|
||||
(const_int 52)
|
||||
(const_int 68))))])
|
||||
|
||||
(define_insn "call_value_internal_reg"
|
||||
[(set (match_operand 0 "" "=rf")
|
||||
(call (mem:SI (match_operand:SI 1 "register_operand" "r"))
|
||||
(match_operand 2 "" "i")))
|
||||
(call (mem:SI (reg:SI 22))
|
||||
(match_operand 1 "" "i")))
|
||||
(clobber (reg:SI 2))
|
||||
(use (const_int 1))]
|
||||
""
|
||||
"*
|
||||
{
|
||||
if (TARGET_FAST_INDIRECT_CALLS)
|
||||
return \"ble 0(%%sr4,%r1)\;copy %%r31,%%r2\";
|
||||
rtx xoperands[2];
|
||||
|
||||
/* Yuk! bl may not be able to reach $$dyncall. */
|
||||
if (TARGET_PORTABLE_RUNTIME || TARGET_MILLICODE_LONG_CALLS)
|
||||
return \"copy %r1,%%r22\;ldil L%%$$dyncall,%%r31\;ldo R%%$$dyncall(%%r31),%%r31\;blr 0,%%r2\;bv,n 0(%%r31)\;nop\";
|
||||
else
|
||||
return \"copy %r1,%%r22\;.CALL\\tARGW0=GR\;bl $$dyncall,%%r31\;copy %%r31,%%r2\";
|
||||
/* First the special case for kernels, level 0 systems, etc. */
|
||||
if (TARGET_NO_SPACE_REGS)
|
||||
return \"ble 0(%%sr4,%%r22)\;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[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 "length")
|
||||
(if_then_else (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME")
|
||||
(const_int 0))
|
||||
(eq (symbol_ref "TARGET_MILLICODE_LONG_CALLS")
|
||||
(const_int 0)))
|
||||
(const_int 12)
|
||||
(const_int 24)))])
|
||||
(cond [
|
||||
;; First NO_SPACE_REGS
|
||||
(ne (symbol_ref "TARGET_NO_SPACE_REGS")
|
||||
(const_int 0))
|
||||
(const_int 8)
|
||||
|
||||
;; 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.
|
||||
|
||||
|
@ -4153,7 +4436,7 @@
|
|||
;; Short branch has length of 4
|
||||
;; Long branch has length of 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 8))
|
||||
|
||||
|
@ -4163,12 +4446,12 @@
|
|||
(if_then_else (lt (match_dup 3) (pc))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 24))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 24)
|
||||
(const_int 28))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 24)
|
||||
(const_int 28)))
|
||||
;; Loop counter in memory case.
|
||||
|
@ -4176,12 +4459,12 @@
|
|||
(if_then_else (lt (match_dup 3) (pc))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16))))))])
|
||||
|
||||
|
@ -4209,7 +4492,7 @@
|
|||
;; Short branch has length of 4
|
||||
;; Long branch has length of 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 8))
|
||||
|
||||
|
@ -4219,12 +4502,12 @@
|
|||
(if_then_else (lt (match_dup 3) (pc))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 24))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 24)
|
||||
(const_int 28))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 24)
|
||||
(const_int 28)))
|
||||
;; Loop counter in memory case.
|
||||
|
@ -4232,12 +4515,12 @@
|
|||
(if_then_else (lt (match_dup 3) (pc))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16))))))])
|
||||
|
||||
|
@ -4260,7 +4543,7 @@
|
|||
;; Short branch has length of 4
|
||||
;; Long branch has length of 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 8))
|
||||
|
||||
|
@ -4270,19 +4553,19 @@
|
|||
(if_then_else (lt (match_dup 3) (pc))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16)))
|
||||
;; Loop counter in memory case.
|
||||
;; Extra goo to deal with additional reload insns.
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 8)
|
||||
(const_int 12)))))])
|
||||
|
||||
|
@ -4306,7 +4589,7 @@
|
|||
;; Short branch has length of 4
|
||||
;; Long branch has length of 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 8))
|
||||
|
||||
|
@ -4316,19 +4599,19 @@
|
|||
(if_then_else (lt (match_dup 3) (pc))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16))
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 12)
|
||||
(const_int 16)))
|
||||
;; Loop counter in memory case.
|
||||
;; Extra goo to deal with additional reload insns.
|
||||
(if_then_else
|
||||
(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
|
||||
(const_int 8188))
|
||||
(const_int 8184))
|
||||
(const_int 8)
|
||||
(const_int 12)))))])
|
||||
|
||||
|
|
Loading…
Reference in New Issue