* config/tc-sparc.c (sparc_relax): New.

(md_longopts): Add -relax and -no-relax options.
	(md_parse_options, md_show_usage): Likewise.
	(md_apply_fix3): Optimize tail call into branch always if possible.
This commit is contained in:
Jakub Jelinek 2000-05-26 06:45:55 +00:00
parent f7775d95e6
commit 6faf3d667f
2 changed files with 109 additions and 1 deletions

View File

@ -1,3 +1,10 @@
2000-05-26 Jakub Jelinek <jakub@redhat.com>
* config/tc-sparc.c (sparc_relax): New.
(md_longopts): Add -relax and -no-relax options.
(md_parse_options, md_show_usage): Likewise.
(md_apply_fix3): Optimize tail call into branch always if possible.
Thu May 4 15:27:07 2000 Donald Lindsay <dlindsay@cygnus.com>
* config/tc-d10v.c (write_2_short, parallel_ok, md_assemble,

View File

@ -91,6 +91,9 @@ static enum sparc_opcode_arch_val warn_after_architecture;
has been used in -64. */
static int no_undeclared_regs;
/* Non-zero if we should try to relax jumps and calls. */
static int sparc_relax;
/* Non-zero if we are generating PIC code. */
int sparc_pic_code;
@ -415,6 +418,10 @@ struct option md_longopts[] = {
#define OPTION_UNDECLARED_REGS (OPTION_MD_BASE + 13)
{"undeclared-regs", no_argument, NULL, OPTION_UNDECLARED_REGS},
#endif
#define OPTION_RELAX (OPTION_MD_BASE + 14)
{"relax", no_argument, NULL, OPTION_RELAX},
#define OPTION_NO_RELAX (OPTION_MD_BASE + 15)
{"no-relax", no_argument, NULL, OPTION_NO_RELAX},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof(md_longopts);
@ -574,6 +581,14 @@ md_parse_option (c, arg)
break;
#endif
case OPTION_RELAX:
sparc_relax = 1;
break;
case OPTION_NO_RELAX:
sparc_relax = 0;
break;
default:
return 0;
}
@ -605,7 +620,9 @@ md_show_usage (stream)
specify variant of SPARC architecture\n\
-bump warn when assembler switches architectures\n\
-sparc ignored\n\
--enforce-aligned-data force .long, etc., to be aligned correctly\n"));
--enforce-aligned-data force .long, etc., to be aligned correctly\n\
-relax relax jumps and branches (default)\n\
-no-relax avoid changing any jumps and branches\n"));
#ifdef OBJ_AOUT
fprintf (stream, _("\
-k generate PIC\n"));
@ -2915,7 +2932,91 @@ md_apply_fix3 (fixP, value, segment)
|| fixP->fx_addsy == NULL
|| symbol_section_p (fixP->fx_addsy))
++val;
insn |= val & 0x3fffffff;
/* See if we have a delay slot */
if (sparc_relax && fixP->fx_where + 8 <= fixP->fx_frag->fr_fix)
{
#define G0 0
#define O7 15
#define XCC (2 << 20)
#define COND(x) (((x)&0xf)<<25)
#define CONDA COND(0x8)
#define INSN_BPA (F2(0,1) | CONDA | BPRED | XCC)
#define INSN_BA (F2(0,2) | CONDA)
#define INSN_OR F3(2, 0x2, 0)
#define INSN_NOP F2(0,4)
long delay;
/* If the instruction is a call with either:
restore
arithmetic instruction with rd == %o7
where rs1 != %o7 and rs2 if it is register != %o7
then we can optimize if the call destination is near
by changing the call into a branch always. */
if (INSN_BIG_ENDIAN)
delay = bfd_getb32 ((unsigned char *) buf + 4);
else
delay = bfd_getl32 ((unsigned char *) buf + 4);
if ((insn & OP(~0)) != OP(1) || (delay & OP(~0)) != OP(2))
break;
if ((delay & OP3(~0)) != OP3(0x3d) /* restore */
&& ((delay & OP3(0x28)) != 0 /* arithmetic */
|| ((delay & RD(~0)) != RD(O7))))
break;
if ((delay & RS1(~0)) == RS1(O7)
|| ((delay & F3I(~0)) == 0
&& (delay & RS2(~0)) == RS2(O7)))
break;
/* Ensure the branch will fit into simm22. */
if ((val & 0x3fe00000)
&& (val & 0x3fe00000) != 0x3fe00000)
break;
/* Check if the arch is v9 and branch will fit
into simm19. */
if (((val & 0x3c0000) == 0
|| (val & 0x3c0000) == 0x3c0000)
&& (sparc_arch_size == 64
|| current_architecture >= SPARC_OPCODE_ARCH_V9))
/* ba,pt %xcc */
insn = INSN_BPA | (val & 0x7ffff);
else
/* ba */
insn = INSN_BA | (val & 0x3fffff);
if (fixP->fx_where >= 4
&& ((delay & (0xffffffff ^ RS1(~0)))
== (INSN_OR | RD(O7) | RS2(G0))))
{
long setter;
int reg;
if (INSN_BIG_ENDIAN)
setter = bfd_getb32 ((unsigned char *) buf - 4);
else
setter = bfd_getl32 ((unsigned char *) buf - 4);
if ((setter & (0xffffffff ^ RD(~0)))
!= (INSN_OR | RS1(O7) | RS2(G0)))
break;
/* The sequence was
or %o7, %g0, %rN
call foo
or %rN, %g0, %o7
If call foo was replaced with ba, replace
or %rN, %g0, %o7 with nop. */
reg = (delay & RS1(~0)) >> 14;
if (reg != ((setter & RD(~0)) >> 25)
|| reg == G0 || reg == O7)
break;
if (INSN_BIG_ENDIAN)
bfd_putb32 (INSN_NOP, (unsigned char *) buf + 4);
else
bfd_putl32 (INSN_NOP, (unsigned char *) buf + 4);
}
}
break;
case BFD_RELOC_SPARC_11: