Commit 5fad1c24 by John David Anglin Committed by John David Anglin

pa.c (update_total_code_bytes): New function.

        * pa.c (update_total_code_bytes): New function.
	(last_address): Number of bytes output for a function and its
	associated thunks.
	(compute_frame_size): Use BITS_PER_UNIT.
	(pa_output_function_epilogue): Compute last_address.  Use
	update_total_code_bytes.
	(output_lbranch): Handle long branch on portable runtime.
	(attr_length_millicode_call, attr_length_call,
	attr_length_indirect_call): Only use total_code_bytes for calls in
	the text section.
	(output_call): Only use an indirect call sequence when the target is
	not local.
	(pa_asm_output_mi_thunk): Handle updating of total_code_bytes.  Improve
	test to determine when an IA-relative branch can be used.  Add various
	long branch sequences.  Avoid using an indirect branch on all ports
	except SOM.

From-SVN: r68677
parent 342e2b74
2003-06-29 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
* pa.c (update_total_code_bytes): New function.
(last_address): Number of bytes output for a function and its
associated thunks.
(compute_frame_size): Use BITS_PER_UNIT.
(pa_output_function_epilogue): Compute last_address. Use
update_total_code_bytes.
(output_lbranch): Handle long branch on portable runtime.
(attr_length_millicode_call, attr_length_call,
attr_length_indirect_call): Only use total_code_bytes for calls in
the text section.
(output_call): Only use an indirect call sequence when the target is
not local.
(pa_asm_output_mi_thunk): Handle updating of total_code_bytes. Improve
test to determine when an IA-relative branch can be used. Add various
long branch sequences. Avoid using an indirect branch on all ports
except SOM.
2003-06-29 Ulrich Weigand <uweigand@de.ibm.com> 2003-06-29 Ulrich Weigand <uweigand@de.ibm.com>
* expr.c (clear_by_pieces): Fix prototype. * expr.c (clear_by_pieces): Fix prototype.
......
...@@ -113,6 +113,7 @@ static void store_reg_modify PARAMS ((int, int, int)); ...@@ -113,6 +113,7 @@ static void store_reg_modify PARAMS ((int, int, int));
static void load_reg PARAMS ((int, int, int)); static void load_reg PARAMS ((int, int, int));
static void set_reg_plus_d PARAMS ((int, int, int, int)); static void set_reg_plus_d PARAMS ((int, int, int, int));
static void pa_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT)); static void pa_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void update_total_code_bytes PARAMS ((int));
static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int)); static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int pa_adjust_priority PARAMS ((rtx, int)); static int pa_adjust_priority PARAMS ((rtx, int));
...@@ -169,10 +170,15 @@ static int gr_saved, fr_saved; ...@@ -169,10 +170,15 @@ static int gr_saved, fr_saved;
static rtx find_addr_reg PARAMS ((rtx)); static rtx find_addr_reg PARAMS ((rtx));
/* Keep track of the number of bytes we have output in the CODE subspaces /* Keep track of the number of bytes we have output in the CODE subspace
during this compilation so we'll know when to emit inline long-calls. */ during this compilation so we'll know when to emit inline long-calls. */
unsigned long total_code_bytes; unsigned long total_code_bytes;
/* The last address of the previous function plus the number of bytes in
associated thunks that have been output. This is used to determine if
a thunk can use an IA-relative branch to reach its target function. */
static int last_address;
/* Variables to handle plabels that we discover are necessary at assembly /* Variables to handle plabels that we discover are necessary at assembly
output time. They are output after the current function. */ output time. They are output after the current function. */
struct deferred_plabel GTY(()) struct deferred_plabel GTY(())
...@@ -3292,8 +3298,8 @@ compute_frame_size (size, fregs_live) ...@@ -3292,8 +3298,8 @@ compute_frame_size (size, fregs_live)
size += TARGET_64BIT ? 48 : 32; size += TARGET_64BIT ? 48 : 32;
/* Finally, round to the preferred stack boundary. */ /* Finally, round to the preferred stack boundary. */
return ((size + PREFERRED_STACK_BOUNDARY / 8 - 1) return ((size + PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1)
& ~(PREFERRED_STACK_BOUNDARY / 8 - 1)); & ~(PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1));
} }
/* Generate the assembly code for function entry. FILE is a stdio /* Generate the assembly code for function entry. FILE is a stdio
...@@ -3681,6 +3687,30 @@ load_reg (reg, disp, base) ...@@ -3681,6 +3687,30 @@ load_reg (reg, disp, base)
} }
} }
/* Update the total code bytes output to the text section. */
static void
update_total_code_bytes (nbytes)
int nbytes;
{
if ((TARGET_PORTABLE_RUNTIME || !TARGET_GAS || !TARGET_SOM)
&& in_text_section ())
{
if (INSN_ADDRESSES_SET_P ())
{
unsigned long old_total = total_code_bytes;
total_code_bytes += nbytes;
/* Be prepared to handle overflows. */
if (old_total > total_code_bytes)
total_code_bytes = -1;
}
else
total_code_bytes = -1;
}
}
/* This function generates the assembly code for function exit. /* This function generates the assembly code for function exit.
Args are as for output_function_prologue (). Args are as for output_function_prologue ().
...@@ -3694,9 +3724,10 @@ pa_output_function_epilogue (file, size) ...@@ -3694,9 +3724,10 @@ pa_output_function_epilogue (file, size)
FILE *file; FILE *file;
HOST_WIDE_INT size ATTRIBUTE_UNUSED; HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{ {
int last_address = 0;
rtx insn = get_last_insn (); rtx insn = get_last_insn ();
last_address = 0;
/* hppa_expand_epilogue does the dirty work now. We just need /* hppa_expand_epilogue does the dirty work now. We just need
to output the assembler directives which denote the end to output the assembler directives which denote the end
of a function. of a function.
...@@ -3724,29 +3755,18 @@ pa_output_function_epilogue (file, size) ...@@ -3724,29 +3755,18 @@ pa_output_function_epilogue (file, size)
fputs ("\t.EXIT\n\t.PROCEND\n", file); fputs ("\t.EXIT\n\t.PROCEND\n", file);
/* Finally, update the total number of code bytes output so far. */ if (INSN_ADDRESSES_SET_P ())
if ((TARGET_PORTABLE_RUNTIME || !TARGET_GAS || !TARGET_SOM)
&& !flag_function_sections)
{ {
if (INSN_ADDRESSES_SET_P ()) insn = get_last_nonnote_insn ();
{ last_address += INSN_ADDRESSES (INSN_UID (insn));
unsigned long old_total = total_code_bytes; if (INSN_P (insn))
last_address += insn_default_length (insn);
insn = get_last_nonnote_insn (); last_address = ((last_address + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
last_address += INSN_ADDRESSES (INSN_UID (insn)); & ~(FUNCTION_BOUNDARY / BITS_PER_UNIT - 1));
if (INSN_P (insn))
last_address += insn_default_length (insn);
total_code_bytes += last_address;
total_code_bytes += FUNCTION_BOUNDARY / BITS_PER_UNIT;
/* Be prepared to handle overflows. */
if (old_total > total_code_bytes)
total_code_bytes = -1;
}
else
total_code_bytes = -1;
} }
/* Finally, update the total number of code bytes output so far. */
update_total_code_bytes (last_address);
} }
void void
...@@ -5904,7 +5924,13 @@ output_lbranch (dest, insn) ...@@ -5904,7 +5924,13 @@ output_lbranch (dest, insn)
output_asm_insn ("stw %%r1,-12(%%r30)", xoperands); output_asm_insn ("stw %%r1,-12(%%r30)", xoperands);
} }
if (flag_pic) if (TARGET_PORTABLE_RUNTIME)
{
output_asm_insn ("ldil L'%0,%%r1", xoperands);
output_asm_insn ("ldo R'%0(%%r1),%%r1", xoperands);
output_asm_insn ("bv %%r0(%%r1)", xoperands);
}
else if (flag_pic)
{ {
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
if (TARGET_SOM || !TARGET_GAS) if (TARGET_SOM || !TARGET_GAS)
...@@ -6545,11 +6571,12 @@ attr_length_millicode_call (insn) ...@@ -6545,11 +6571,12 @@ attr_length_millicode_call (insn)
rtx insn; rtx insn;
{ {
unsigned long distance = -1; unsigned long distance = -1;
unsigned long total = in_text_section () ? total_code_bytes : 0;
if (INSN_ADDRESSES_SET_P ()) if (INSN_ADDRESSES_SET_P ())
{ {
distance = (total_code_bytes + insn_current_reference_address (insn)); distance = (total + insn_current_reference_address (insn));
if (distance < total_code_bytes) if (distance < total)
distance = -1; distance = -1;
} }
...@@ -6741,11 +6768,12 @@ attr_length_call (insn, sibcall) ...@@ -6741,11 +6768,12 @@ attr_length_call (insn, sibcall)
int sibcall; int sibcall;
{ {
unsigned long distance = -1; unsigned long distance = -1;
unsigned long total = in_text_section ()? total_code_bytes : 0;
if (INSN_ADDRESSES_SET_P ()) if (INSN_ADDRESSES_SET_P ())
{ {
distance = (total_code_bytes + insn_current_reference_address (insn)); distance = (total + insn_current_reference_address (insn));
if (distance < total_code_bytes) if (distance < total)
distance = -1; distance = -1;
} }
...@@ -6813,12 +6841,15 @@ output_call (insn, call_dest, sibcall) ...@@ -6813,12 +6841,15 @@ output_call (insn, call_dest, sibcall)
int delay_insn_deleted = 0; int delay_insn_deleted = 0;
int delay_slot_filled = 0; int delay_slot_filled = 0;
int seq_length = dbr_sequence_length (); int seq_length = dbr_sequence_length ();
tree call_decl = SYMBOL_REF_DECL (call_dest);
int local_call = call_decl && !TREE_PUBLIC (call_decl);
rtx xoperands[2]; rtx xoperands[2];
xoperands[0] = call_dest; xoperands[0] = call_dest;
/* Handle the common case where we're sure that the branch will reach /* Handle the common case where we're sure that the branch will reach
the beginning of the $CODE$ subspace. */ the beginning of the "$CODE$" subspace. This is the beginning of
the current function if we are in a named section. */
if (!TARGET_LONG_CALLS && attr_length_call (insn, sibcall) == 8) if (!TARGET_LONG_CALLS && attr_length_call (insn, sibcall) == 8)
{ {
xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2); xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
...@@ -6826,7 +6857,7 @@ output_call (insn, call_dest, sibcall) ...@@ -6826,7 +6857,7 @@ output_call (insn, call_dest, sibcall)
} }
else else
{ {
if (TARGET_64BIT) if (TARGET_64BIT && !local_call)
{ {
/* ??? As far as I can tell, the HP linker doesn't support the /* ??? As far as I can tell, the HP linker doesn't support the
long pc-relative sequence described in the 64-bit runtime long pc-relative sequence described in the 64-bit runtime
...@@ -6878,9 +6909,10 @@ output_call (insn, call_dest, sibcall) ...@@ -6878,9 +6909,10 @@ output_call (insn, call_dest, sibcall)
/* Emit a long call. There are several different sequences /* Emit a long call. There are several different sequences
of increasing length and complexity. In most cases, of increasing length and complexity. In most cases,
they don't allow an instruction in the delay slot. */ they don't allow an instruction in the delay slot. */
if (!(TARGET_LONG_ABS_CALL && !flag_pic) if (!((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
&& !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL) && !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
&& !(TARGET_GAS && TARGET_LONG_PIC_PCREL_CALL)) && !(TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
&& !TARGET_64BIT)
indirect_call = 1; indirect_call = 1;
if (seq_length != 0 if (seq_length != 0
...@@ -6900,12 +6932,13 @@ output_call (insn, call_dest, sibcall) ...@@ -6900,12 +6932,13 @@ output_call (insn, call_dest, sibcall)
delay_insn_deleted = 1; delay_insn_deleted = 1;
} }
if (TARGET_LONG_ABS_CALL && !flag_pic) if ((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
{ {
/* This is the best sequence for making long calls in /* This is the best sequence for making long calls in
non-pic code. Unfortunately, GNU ld doesn't provide non-pic code. Unfortunately, GNU ld doesn't provide
the stub needed for external calls, and GAS's support the stub needed for external calls, and GAS's support
for this with the SOM linker is buggy. */ for this with the SOM linker is buggy. It is safe
to use this for local calls. */
output_asm_insn ("ldil L'%0,%%r1", xoperands); output_asm_insn ("ldil L'%0,%%r1", xoperands);
if (sibcall) if (sibcall)
output_asm_insn ("be R'%0(%%sr4,%%r1)", xoperands); output_asm_insn ("be R'%0(%%sr4,%%r1)", xoperands);
...@@ -6923,7 +6956,8 @@ output_call (insn, call_dest, sibcall) ...@@ -6923,7 +6956,8 @@ output_call (insn, call_dest, sibcall)
} }
else else
{ {
if (TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL) if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
|| (TARGET_64BIT && !TARGET_GAS))
{ {
/* The HP assembler and linker can handle relocations /* The HP assembler and linker can handle relocations
for the difference of two symbols. GAS and the HP for the difference of two symbols. GAS and the HP
...@@ -6936,7 +6970,7 @@ output_call (insn, call_dest, sibcall) ...@@ -6936,7 +6970,7 @@ output_call (insn, call_dest, sibcall)
CODE_LABEL_NUMBER (xoperands[1])); CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands); output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
} }
else if (TARGET_GAS && TARGET_LONG_PIC_PCREL_CALL) else if (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
{ {
/* GAS currently can't generate the relocations that /* GAS currently can't generate the relocations that
are needed for the SOM linker under HP-UX using this are needed for the SOM linker under HP-UX using this
...@@ -7075,11 +7109,9 @@ output_call (insn, call_dest, sibcall) ...@@ -7075,11 +7109,9 @@ output_call (insn, call_dest, sibcall)
CODE_LABEL_NUMBER (xoperands[1])); CODE_LABEL_NUMBER (xoperands[1]));
} }
else else
/* ??? This branch may not reach its target. */
output_asm_insn ("nop\n\tb,n %0", xoperands); output_asm_insn ("nop\n\tb,n %0", xoperands);
} }
else else
/* ??? This branch may not reach its target. */
output_asm_insn ("b,n %0", xoperands); output_asm_insn ("b,n %0", xoperands);
/* Delete the jump. */ /* Delete the jump. */
...@@ -7101,11 +7133,12 @@ attr_length_indirect_call (insn) ...@@ -7101,11 +7133,12 @@ attr_length_indirect_call (insn)
rtx insn; rtx insn;
{ {
unsigned long distance = -1; unsigned long distance = -1;
unsigned long total = in_text_section () ? total_code_bytes : 0;
if (INSN_ADDRESSES_SET_P ()) if (INSN_ADDRESSES_SET_P ())
{ {
distance = (total_code_bytes + insn_current_reference_address (insn)); distance = (total + insn_current_reference_address (insn));
if (distance < total_code_bytes) if (distance < total)
distance = -1; distance = -1;
} }
...@@ -7280,81 +7313,239 @@ pa_asm_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) ...@@ -7280,81 +7313,239 @@ pa_asm_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED; HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
tree function; tree function;
{ {
const char *target_name = XSTR (XEXP (DECL_RTL (function), 0), 0); const char *fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
const char *tname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
int val_14 = VAL_14_BITS_P (delta);
int nbytes = 0;
static unsigned int current_thunk_number; static unsigned int current_thunk_number;
char label[16]; char label[16];
const char *lab;
ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number); ASM_OUTPUT_LABEL (file, tname);
lab = (*targetm.strip_name_encoding) (label); fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=0,NO_CALLS\n\t.ENTRY\n");
target_name = (*targetm.strip_name_encoding) (target_name);
/* FIXME: total_code_bytes is not handled correctly in files with fname = (*targetm.strip_name_encoding) (fname);
mi thunks. */ tname = (*targetm.strip_name_encoding) (tname);
pa_output_function_prologue (file, 0);
if (VAL_14_BITS_P (delta)) /* Output the thunk. We know that the function is in the same
{ translation unit (i.e., the same space) as the thunk, and that
if (!TARGET_64BIT && !TARGET_PORTABLE_RUNTIME && flag_pic) thunks are output after their method. Thus, we don't need an
{ external branch to reach the function. With SOM and GAS,
fprintf (file, "\taddil LT'%s,%%r19\n", lab); functions and thunks are effectively in different sections.
fprintf (file, "\tldw RT'%s(%%r1),%%r22\n", lab); Thus, we can always use a IA-relative branch and the linker
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n"); will add a long branch stub if necessary.
fprintf (file, "\tbb,>=,n %%r22,30,.+16\n");
fprintf (file, "\tdepi 0,31,2,%%r22\n"); However, we have to be careful when generating PIC code on the
fprintf (file, "\tldw 4(%%sr0,%%r22),%%r19\n"); SOM port to ensure that the sequence does not transfer to an
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n"); import stub for the target function as this could clobber the
return value saved at SP-24. This would also apply to the
32-bit linux port if the multi-space model is implemented. */
if ((!TARGET_LONG_CALLS && TARGET_SOM && !TARGET_PORTABLE_RUNTIME
&& !(flag_pic && TREE_PUBLIC (function))
&& (TARGET_GAS || last_address < 262132))
|| (!TARGET_LONG_CALLS && !TARGET_SOM && !TARGET_PORTABLE_RUNTIME
&& ((targetm.have_named_sections
&& DECL_SECTION_NAME (thunk_fndecl) != NULL
/* The GNU 64-bit linker has rather poor stub management.
So, we use a long branch from thunks that aren't in
the same section as the target function. */
&& ((!TARGET_64BIT
&& (DECL_SECTION_NAME (thunk_fndecl)
!= DECL_SECTION_NAME (function)))
|| ((DECL_SECTION_NAME (thunk_fndecl)
== DECL_SECTION_NAME (function))
&& last_address < 262132)))
|| (!targetm.have_named_sections && last_address < 262132))))
{
if (val_14)
{
fprintf (file, "\tb %s\n\tldo " HOST_WIDE_INT_PRINT_DEC
"(%%r26),%%r26\n", fname, delta);
nbytes += 8;
}
else
{
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
",%%r26\n", delta);
fprintf (file, "\tb %s\n\tldo R'" HOST_WIDE_INT_PRINT_DEC
"(%%r1),%%r26\n", fname, delta);
nbytes += 12;
}
}
else if (TARGET_64BIT)
{
/* We only have one call-clobbered scratch register, so we can't
make use of the delay slot if delta doesn't fit in 14 bits. */
if (!val_14)
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
",%%r26\n\tldo R'" HOST_WIDE_INT_PRINT_DEC
"(%%r1),%%r26\n", delta, delta);
fprintf (file, "\tb,l .+8,%%r1\n");
if (TARGET_GAS)
{
fprintf (file, "\taddil L'%s-$PIC_pcrel$0+4,%%r1\n", fname);
fprintf (file, "\tldo R'%s-$PIC_pcrel$0+8(%%r1),%%r1\n", fname);
}
else
{
int off = val_14 ? 8 : 16;
fprintf (file, "\taddil L'%s-%s-%d,%%r1\n", fname, tname, off);
fprintf (file, "\tldo R'%s-%s-%d(%%r1),%%r1\n", fname, tname, off);
}
if (val_14)
{
fprintf (file, "\tbv %%r0(%%r1)\n\tldo ");
fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
nbytes += 20;
}
else
{
fprintf (file, "\tbv,n %%r0(%%r1)\n");
nbytes += 24;
}
}
else if (TARGET_PORTABLE_RUNTIME)
{
fprintf (file, "\tldil L'%s,%%r1\n", fname);
fprintf (file, "\tldo R'%s(%%r1),%%r22\n", fname);
if (val_14)
{
fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
nbytes += 16;
}
else
{
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
",%%r26\n", delta);
fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
nbytes += 20;
}
}
else if (TARGET_SOM && flag_pic && TREE_PUBLIC (function))
{
/* The function is accessible from outside this module. The only
way to avoid an import stub between the thunk and function is to
call the function directly with an indirect sequence similar to
that used by $$dyncall. This is possible because $$dyncall acts
as the import stub in an indirect call. */
const char *lab;
ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number);
lab = (*targetm.strip_name_encoding) (label);
fprintf (file, "\taddil LT'%s,%%r19\n", lab);
fprintf (file, "\tldw RT'%s(%%r1),%%r22\n", lab);
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
fprintf (file, "\tbb,>=,n %%r22,30,.+16\n");
fprintf (file, "\tdepi 0,31,2,%%r22\n");
fprintf (file, "\tldw 4(%%sr0,%%r22),%%r19\n");
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
if (!val_14)
{
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
",%%r26\n", delta);
nbytes += 4;
}
if (TARGET_PA_20)
{
fprintf (file, "\tbve (%%r22)\n\tldo ");
nbytes += 36;
}
else
{
if (TARGET_NO_SPACE_REGS) if (TARGET_NO_SPACE_REGS)
fprintf (file, "\tbe 0(%%sr4,%%r22)\n\tldo "); {
fprintf (file, "\tbe 0(%%sr4,%%r22)\n\tldo ");
nbytes += 36;
}
else else
{ {
fprintf (file, "\tldsid (%%sr0,%%r22),%%r1\n"); fprintf (file, "\tldsid (%%sr0,%%r22),%%r1\n");
fprintf (file, "\tmtsp %%r1,%%sr0\n"); fprintf (file, "\tmtsp %%r21,%%sr0\n");
fprintf (file, "\tbe 0(%%sr0,%%r22)\n\tldo "); fprintf (file, "\tbe 0(%%sr0,%%r22)\n\tldo ");
nbytes += 44;
} }
}
if (val_14)
fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
else
fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
}
else if (flag_pic)
{
if (TARGET_PA_20)
fprintf (file, "\tb,l .+8,%%r1\n");
else
fprintf (file, "\tbl .+8,%%r1\n");
if (TARGET_SOM || !TARGET_GAS)
{
fprintf (file, "\taddil L'%s-%s-8,%%r1\n", fname, tname);
fprintf (file, "\tldo R'%s-%s-8(%%r1),%%r22\n", fname, tname);
}
else
{
fprintf (file, "\taddil L'%s-$PIC_pcrel$0+4,%%r1\n", fname);
fprintf (file, "\tldo R'%s-$PIC_pcrel$0+8(%%r1),%%r22\n", fname);
}
if (val_14)
{
fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta); fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
nbytes += 20;
} }
else else
fprintf (file, "\tb %s\n\tldo " HOST_WIDE_INT_PRINT_DEC {
"(%%r26),%%r26\n", fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
target_name, delta); ",%%r26\n", delta);
fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
nbytes += 24;
}
} }
else else
{ {
if (!TARGET_64BIT && !TARGET_PORTABLE_RUNTIME && flag_pic) if (!val_14)
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC ",%%r26\n", delta);
fprintf (file, "\tldil L'%s,%%r22\n", fname);
fprintf (file, "\tbe R'%s(%%sr4,%%r22)\n\tldo ", fname);
if (val_14)
{ {
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
",%%r26\n\tldo R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", nbytes += 12;
delta, delta);
fprintf (file, "\taddil LT'%s,%%r19\n", lab);
fprintf (file, "\tldw RT'%s(%%r1),%%r22\n", lab);
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
fprintf (file, "\tbb,>=,n %%r22,30,.+16\n");
fprintf (file, "\tdepi 0,31,2,%%r22\n");
fprintf (file, "\tldw 4(%%sr0,%%r22),%%r19\n");
fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
if (TARGET_NO_SPACE_REGS)
fprintf (file, "\tbe 0(%%sr4,%%r22)");
else
{
fprintf (file, "\tldsid (%%sr0,%%r22),%%r1\n");
fprintf (file, "\tmtsp %%r1,%%sr0\n");
fprintf (file, "\tbe,n 0(%%sr0,%%r22)\n");
}
} }
else else
fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC {
",%%r26\n\tb %s\n\tldo R'" HOST_WIDE_INT_PRINT_DEC fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
"(%%r1),%%r26\n", delta, target_name, delta); nbytes += 16;
}
} }
fprintf (file, "\t.EXIT\n\t.PROCEND\n"); fprintf (file, "\t.EXIT\n\t.PROCEND\n");
if (! TARGET_64BIT && ! TARGET_PORTABLE_RUNTIME && flag_pic)
if (TARGET_SOM && flag_pic && TREE_PUBLIC (function))
{ {
data_section (); data_section ();
fprintf (file, "\t.align 4\n"); fprintf (file, "\t.align 4\n");
(*targetm.asm_out.internal_label) (file, "LTHN", current_thunk_number); ASM_OUTPUT_LABEL (file, label);
fprintf (file, "\t.word P'%s\n", target_name); fprintf (file, "\t.word P'%s\n", fname);
function_section (thunk_fndecl); function_section (thunk_fndecl);
} }
current_thunk_number++; current_thunk_number++;
nbytes = ((nbytes + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
& ~(FUNCTION_BOUNDARY / BITS_PER_UNIT - 1));
last_address += nbytes;
update_total_code_bytes (nbytes);
} }
/* Only direct calls to static functions are allowed to be sibling (tail) /* Only direct calls to static functions are allowed to be sibling (tail)
......
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