Commit 568de9bb by John David Anglin

pa.c (pa_output_pic_pcrel_sequence): New.

	* config/pa/pa.c (pa_output_pic_pcrel_sequence): New.
	(pa_output_lbranch): Use pa_output_pic_pcrel_sequence.
	(pa_output_millicode_call): Likewise.
	(pa_output_call): Likewise.
	(pa_output_indirect_call): Likewise.
	(pa_asm_output_mi_thunk): Likewise.

From-SVN: r237543
parent 6f820b68
2016-06-16 John David Anglin <danglin@gcc.gnu.org>
* config/pa/pa.c (pa_output_pic_pcrel_sequence): New.
(pa_output_lbranch): Use pa_output_pic_pcrel_sequence.
(pa_output_millicode_call): Likewise.
(pa_output_call): Likewise.
(pa_output_indirect_call): Likewise.
(pa_asm_output_mi_thunk): Likewise.
2016-06-16 Bernhard Reutner-Fischer <aldot@gcc.gnu.org> 2016-06-16 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
* doc/invoke.texi (x86 Options): Fix -mno-fp-ret-in-387 typo. * doc/invoke.texi (x86 Options): Fix -mno-fp-ret-in-387 typo.
......
...@@ -6710,6 +6710,57 @@ pa_output_cbranch (rtx *operands, int negated, rtx_insn *insn) ...@@ -6710,6 +6710,57 @@ pa_output_cbranch (rtx *operands, int negated, rtx_insn *insn)
return buf; return buf;
} }
/* Output a PIC pc-relative instruction sequence to load the address of
OPERANDS[0] to register OPERANDS[2]. OPERANDS[0] is a symbol ref
or a code label. OPERANDS[1] specifies the register to use to load
the program counter. OPERANDS[3] may be used for label generation
The sequence is always three instructions in length. The program
counter recorded for PA 1.X is eight bytes more than that for PA 2.0.
Register %r1 is clobbered. */
static void
pa_output_pic_pcrel_sequence (rtx *operands)
{
gcc_assert (SYMBOL_REF_P (operands[0]) || LABEL_P (operands[0]));
if (TARGET_PA_20)
{
/* We can use mfia to determine the current program counter. */
if (TARGET_SOM || !TARGET_GAS)
{
operands[3] = gen_label_rtx ();
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (operands[3]));
output_asm_insn ("mfia %1", operands);
output_asm_insn ("addil L'%0-%l3,%1", operands);
output_asm_insn ("ldo R'%0-%l3(%%r1),%2", operands);
}
else
{
output_asm_insn ("mfia %1", operands);
output_asm_insn ("addil L'%0-$PIC_pcrel$0+12,%1", operands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+16(%%r1),%2", operands);
}
}
else
{
/* We need to use a branch to determine the current program counter. */
output_asm_insn ("{bl|b,l} .+8,%1", operands);
if (TARGET_SOM || !TARGET_GAS)
{
operands[3] = gen_label_rtx ();
output_asm_insn ("addil L'%0-%l3,%1", operands);
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (operands[3]));
output_asm_insn ("ldo R'%0-%l3(%%r1),%2", operands);
}
else
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%1", operands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%2", operands);
}
}
}
/* This routine handles output of long unconditional branches that /* This routine handles output of long unconditional branches that
exceed the maximum range of a simple branch instruction. Since exceed the maximum range of a simple branch instruction. Since
we don't have a register available for the branch, we save register we don't have a register available for the branch, we save register
...@@ -6730,7 +6781,7 @@ pa_output_cbranch (rtx *operands, int negated, rtx_insn *insn) ...@@ -6730,7 +6781,7 @@ pa_output_cbranch (rtx *operands, int negated, rtx_insn *insn)
const char * const char *
pa_output_lbranch (rtx dest, rtx_insn *insn, int xdelay) pa_output_lbranch (rtx dest, rtx_insn *insn, int xdelay)
{ {
rtx xoperands[2]; rtx xoperands[4];
xoperands[0] = dest; xoperands[0] = dest;
...@@ -6800,20 +6851,9 @@ pa_output_lbranch (rtx dest, rtx_insn *insn, int xdelay) ...@@ -6800,20 +6851,9 @@ pa_output_lbranch (rtx dest, rtx_insn *insn, int xdelay)
} }
else if (flag_pic) else if (flag_pic)
{ {
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); xoperands[1] = gen_rtx_REG (Pmode, 1);
if (TARGET_SOM || !TARGET_GAS) xoperands[2] = xoperands[1];
{ pa_output_pic_pcrel_sequence (xoperands);
xoperands[1] = gen_label_rtx ();
output_asm_insn ("addil L'%l0-%l1,%%r1", xoperands);
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R'%l0-%l1(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
}
output_asm_insn ("bv %%r0(%%r1)", xoperands); output_asm_insn ("bv %%r0(%%r1)", xoperands);
} }
else else
...@@ -7642,10 +7682,9 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest) ...@@ -7642,10 +7682,9 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest)
{ {
int attr_length = get_attr_length (insn); int attr_length = get_attr_length (insn);
int seq_length = dbr_sequence_length (); int seq_length = dbr_sequence_length ();
rtx xoperands[3]; rtx xoperands[4];
xoperands[0] = call_dest; xoperands[0] = call_dest;
xoperands[2] = gen_rtx_REG (Pmode, TARGET_64BIT ? 2 : 31);
/* Handle the common case where we are sure that the branch will /* Handle the common case where we are sure that the branch will
reach the beginning of the $CODE$ subspace. The within reach reach the beginning of the $CODE$ subspace. The within reach
...@@ -7657,7 +7696,8 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest) ...@@ -7657,7 +7696,8 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest)
|| (attr_length == 28 || (attr_length == 28
&& get_attr_type (insn) == TYPE_SH_FUNC_ADRS))) && get_attr_type (insn) == TYPE_SH_FUNC_ADRS)))
{ {
output_asm_insn ("{bl|b,l} %0,%2", xoperands); xoperands[1] = gen_rtx_REG (Pmode, TARGET_64BIT ? 2 : 31);
output_asm_insn ("{bl|b,l} %0,%1", xoperands);
} }
else else
{ {
...@@ -7668,22 +7708,9 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest) ...@@ -7668,22 +7708,9 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest)
this doesn't work in shared libraries and other dynamically this doesn't work in shared libraries and other dynamically
loaded objects. Using a pc-relative sequence also avoids loaded objects. Using a pc-relative sequence also avoids
problems related to the implicit use of the gp register. */ problems related to the implicit use of the gp register. */
output_asm_insn ("b,l .+8,%%r1", xoperands); xoperands[1] = gen_rtx_REG (Pmode, 1);
xoperands[2] = xoperands[1];
if (TARGET_GAS) pa_output_pic_pcrel_sequence (xoperands);
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
}
else
{
xoperands[1] = gen_label_rtx ();
output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
}
output_asm_insn ("bve,l (%%r1),%%r2", xoperands); output_asm_insn ("bve,l (%%r1),%%r2", xoperands);
} }
else if (TARGET_PORTABLE_RUNTIME) else if (TARGET_PORTABLE_RUNTIME)
...@@ -7713,27 +7740,12 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest) ...@@ -7713,27 +7740,12 @@ pa_output_millicode_call (rtx_insn *insn, rtx call_dest)
} }
else else
{ {
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); xoperands[1] = gen_rtx_REG (Pmode, 31);
output_asm_insn ("addi 16,%%r1,%%r31", xoperands); xoperands[2] = gen_rtx_REG (Pmode, 1);
pa_output_pic_pcrel_sequence (xoperands);
if (TARGET_SOM || !TARGET_GAS) /* Adjust return address. */
{ output_asm_insn ("ldo {16|24}(%%r31),%%r31", xoperands);
/* The HP assembler can generate relocations for the
difference of two symbols. GAS can do this for a
millicode symbol but not an arbitrary external
symbol when generating SOM output. */
xoperands[1] = gen_label_rtx ();
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[1]));
output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+8,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+12(%%r1),%%r1",
xoperands);
}
/* Jump to our target address in %r1. */ /* Jump to our target address in %r1. */
output_asm_insn ("bv %%r0(%%r1)", xoperands); output_asm_insn ("bv %%r0(%%r1)", xoperands);
...@@ -7811,8 +7823,7 @@ pa_attr_length_call (rtx_insn *insn, int sibcall) ...@@ -7811,8 +7823,7 @@ pa_attr_length_call (rtx_insn *insn, int sibcall)
/* long pc-relative branch sequence. */ /* long pc-relative branch sequence. */
else if (TARGET_LONG_PIC_SDIFF_CALL else if (TARGET_LONG_PIC_SDIFF_CALL
|| (TARGET_GAS && !TARGET_SOM || (TARGET_GAS && !TARGET_SOM && local_call))
&& (TARGET_LONG_PIC_PCREL_CALL || local_call)))
{ {
length += 20; length += 20;
...@@ -7854,7 +7865,7 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall) ...@@ -7854,7 +7865,7 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall)
int seq_length = dbr_sequence_length (); int seq_length = dbr_sequence_length ();
tree call_decl = SYMBOL_REF_DECL (call_dest); tree call_decl = SYMBOL_REF_DECL (call_dest);
int local_call = call_decl && targetm.binds_local_p (call_decl); int local_call = call_decl && targetm.binds_local_p (call_decl);
rtx xoperands[2]; rtx xoperands[4];
xoperands[0] = call_dest; xoperands[0] = call_dest;
...@@ -7918,8 +7929,7 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall) ...@@ -7918,8 +7929,7 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall)
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 || local_call) && !flag_pic) if (!((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
&& !TARGET_LONG_PIC_SDIFF_CALL && !TARGET_LONG_PIC_SDIFF_CALL
&& !(TARGET_GAS && !TARGET_SOM && !(TARGET_GAS && !TARGET_SOM && local_call)
&& (TARGET_LONG_PIC_PCREL_CALL || local_call))
&& !TARGET_64BIT) && !TARGET_64BIT)
indirect_call = 1; indirect_call = 1;
...@@ -7964,33 +7974,23 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall) ...@@ -7964,33 +7974,23 @@ pa_output_call (rtx_insn *insn, rtx call_dest, int sibcall)
} }
else else
{ {
if (TARGET_LONG_PIC_SDIFF_CALL) /* The HP assembler and linker can handle relocations for
{ the difference of two symbols. The HP assembler
/* The HP assembler and linker can handle relocations recognizes the sequence as a pc-relative call and
for the difference of two symbols. The HP assembler the linker provides stubs when needed. */
recognizes the sequence as a pc-relative call and
the linker provides stubs when needed. */ /* GAS currently can't generate the relocations that
xoperands[1] = gen_label_rtx (); are needed for the SOM linker under HP-UX using this
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); sequence. The GNU linker doesn't generate the stubs
output_asm_insn ("addil L'%0-%l1,%%r1", xoperands); that are needed for external calls on TARGET_ELF32
targetm.asm_out.internal_label (asm_out_file, "L", with this sequence. For now, we have to use a longer
CODE_LABEL_NUMBER (xoperands[1])); plabel sequence when using GAS for non local calls. */
output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands); if (TARGET_LONG_PIC_SDIFF_CALL
} || (TARGET_GAS && !TARGET_SOM && local_call))
else if (TARGET_GAS && !TARGET_SOM
&& (TARGET_LONG_PIC_PCREL_CALL || local_call))
{ {
/* GAS currently can't generate the relocations that xoperands[1] = gen_rtx_REG (Pmode, 1);
are needed for the SOM linker under HP-UX using this xoperands[2] = xoperands[1];
sequence. The GNU linker doesn't generate the stubs pa_output_pic_pcrel_sequence (xoperands);
that are needed for external calls on TARGET_ELF32
with this sequence. For now, we have to use a
longer plabel sequence when using GAS. */
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1",
xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1",
xoperands);
} }
else else
{ {
...@@ -8131,7 +8131,7 @@ pa_attr_length_indirect_call (rtx_insn *insn) ...@@ -8131,7 +8131,7 @@ pa_attr_length_indirect_call (rtx_insn *insn)
const char * const char *
pa_output_indirect_call (rtx_insn *insn, rtx call_dest) pa_output_indirect_call (rtx_insn *insn, rtx call_dest)
{ {
rtx xoperands[1]; rtx xoperands[4];
if (TARGET_64BIT) if (TARGET_64BIT)
{ {
...@@ -8171,25 +8171,12 @@ pa_output_indirect_call (rtx_insn *insn, rtx call_dest) ...@@ -8171,25 +8171,12 @@ pa_output_indirect_call (rtx_insn *insn, rtx call_dest)
return "ldil L'$$dyncall,%%r31\n\tldo R'$$dyncall(%%r31),%%r31\n\tblr %%r0,%%r2\n\tbv,n %%r0(%%r31)"; return "ldil L'$$dyncall,%%r31\n\tldo R'$$dyncall(%%r31),%%r31\n\tblr %%r0,%%r2\n\tbv,n %%r0(%%r31)";
/* We need a long PIC call to $$dyncall. */ /* We need a long PIC call to $$dyncall. */
xoperands[0] = NULL_RTX; xoperands[0] = gen_rtx_SYMBOL_REF (Pmode, "$$dyncall");
output_asm_insn ("{bl|b,l} .+8,%%r2", xoperands); xoperands[1] = gen_rtx_REG (Pmode, 2);
if (TARGET_SOM || !TARGET_GAS) xoperands[2] = gen_rtx_REG (Pmode, 1);
{ pa_output_pic_pcrel_sequence (xoperands);
xoperands[0] = gen_label_rtx ();
output_asm_insn ("addil L'$$dyncall-%0,%%r2", xoperands);
targetm.asm_out.internal_label (asm_out_file, "L",
CODE_LABEL_NUMBER (xoperands[0]));
output_asm_insn ("ldo R'$$dyncall-%0(%%r1),%%r1", xoperands);
}
else
{
output_asm_insn ("addil L'$$dyncall-$PIC_pcrel$0+4,%%r2", xoperands);
output_asm_insn ("ldo R'$$dyncall-$PIC_pcrel$0+8(%%r1),%%r1",
xoperands);
}
output_asm_insn ("bv %%r0(%%r1)", xoperands); output_asm_insn ("bv %%r0(%%r1)", xoperands);
output_asm_insn ("ldo 12(%%r2),%%r2", xoperands); return "ldo {12|20}(%%r2),%%r2";
return "";
} }
/* In HPUX 8.0's shared library scheme, special relocations are needed /* In HPUX 8.0's shared library scheme, special relocations are needed
...@@ -8333,6 +8320,8 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, ...@@ -8333,6 +8320,8 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
} }
else if (TARGET_64BIT) else if (TARGET_64BIT)
{ {
rtx xop[4];
/* We only have one call-clobbered scratch register, so we can't /* 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. */ make use of the delay slot if delta doesn't fit in 14 bits. */
if (!val_14) if (!val_14)
...@@ -8341,18 +8330,11 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, ...@@ -8341,18 +8330,11 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
} }
output_asm_insn ("b,l .+8,%%r1", xoperands); /* Load function address into %r1. */
xop[0] = xoperands[0];
if (TARGET_GAS) xop[1] = gen_rtx_REG (Pmode, 1);
{ xop[2] = xop[1];
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands); pa_output_pic_pcrel_sequence (xop);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r1", xoperands);
}
else
{
xoperands[3] = GEN_INT (val_14 ? 8 : 16);
output_asm_insn ("addil L'%0-%1-%3,%%r1", xoperands);
}
if (val_14) if (val_14)
{ {
...@@ -8372,7 +8354,7 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, ...@@ -8372,7 +8354,7 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
output_asm_insn ("ldo R'%0(%%r1),%%r22", xoperands); output_asm_insn ("ldo R'%0(%%r1),%%r22", xoperands);
if (!val_14) if (!val_14)
output_asm_insn ("addil L'%2,%%r26", xoperands); output_asm_insn ("ldil L'%2,%%r26", xoperands);
output_asm_insn ("bv %%r0(%%r22)", xoperands); output_asm_insn ("bv %%r0(%%r22)", xoperands);
...@@ -8383,7 +8365,7 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, ...@@ -8383,7 +8365,7 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
} }
else else
{ {
output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); output_asm_insn ("ldo R'%2(%%r26),%%r26", xoperands);
nbytes += 20; nbytes += 20;
} }
} }
...@@ -8435,18 +8417,13 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, ...@@ -8435,18 +8417,13 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
} }
else if (flag_pic) else if (flag_pic)
{ {
output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands); rtx xop[4];
if (TARGET_SOM || !TARGET_GAS) /* Load function address into %r22. */
{ xop[0] = xoperands[0];
output_asm_insn ("addil L'%0-%1-8,%%r1", xoperands); xop[1] = gen_rtx_REG (Pmode, 1);
output_asm_insn ("ldo R'%0-%1-8(%%r1),%%r22", xoperands); xop[2] = gen_rtx_REG (Pmode, 22);
} pa_output_pic_pcrel_sequence (xop);
else
{
output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r22", xoperands);
}
if (!val_14) if (!val_14)
output_asm_insn ("addil L'%2,%%r26", xoperands); output_asm_insn ("addil L'%2,%%r26", xoperands);
......
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