[patch] m68k: Relax 32-bit relative unconditional branches
Kazu Hirata
kazu@codesourcery.com
Tue Aug 28 05:18:00 GMT 2007
Hi,
Attached is a patch to relax 32-bit relative unconditional branches.
ColdFire ISAC is almost but not quite a superset of ISAB because ISAC
does not have 32-bit relative unconditional branches even though ISAB
does. This is a little inconvenient because if an executable ends up
big, then some branch destinations may not be reachable with available
relative branch instructions.
This patch teaches tc-m68k to relax relative unconditional branches
bral
into
bnel
beql
as shown in the last hunk of this patch.
Nathan says:
"I chose a bne/beq pair on the basis that the Z flag only gets set
when two values are the same, which I guessed happens more rarely
than any other available condition. Thus the first branch should be
taken most of the time.
Without this patch, glibc fails to build when we encoutner a branch
that jumps too far.
Tested on m68k-linux. OK to apply?
Kazu Hirata
gas/
2007-08-27 Nathan Sidwell <nathan@codesourcery.com>
* config/tc-m68k.c (LONG_BRANCH_VIA_COND): New.
(BRANCHBWPL, FRAG_VAR_SIZE): New.
(md_relax_table): Add BRANCHBWPL entries.
(m68k_ip): Choose BRANCHBWPL relaxation if necessary.
(md_assemble): Use FRAG_VAR_SIZE.
(md_convert_frag_1): Add BRANCHBWPL cases.
(md_estimate_size_before_relaz): Likewise.
gas/testsuite/
2007-08-27 Nathan Sidwell <nathan@codesourcery.com>
* gas/m68k/br-isaa.d: Dump relocs too.
* gas/m68k/br-isab.d: Likewise.
* gas/m68k/br-isac.d: Likewise. Adjust for long branch relaxation.
Index: gas/config/tc-m68k.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-m68k.c,v
retrieving revision 1.94
diff -u -d -p -r1.94 tc-m68k.c
--- gas/config/tc-m68k.c 3 Jul 2007 11:01:04 -0000 1.94
+++ gas/config/tc-m68k.c 27 Aug 2007 19:32:12 -0000
@@ -367,6 +367,7 @@ struct m68k_it
((x) & (m68020|m68030|m68040|m68060|cpu32|fido_a|mcfisa_b|mcfisa_c))
#define HAVE_LONG_BRANCH(x) \
((x) & (m68020|m68030|m68040|m68060|cpu32|fido_a|mcfisa_b))
+#define LONG_BRANCH_VIA_COND(x) (HAVE_LONG_COND(x) && !HAVE_LONG_BRANCH(x))
static struct m68k_it the_ins; /* The instruction being assembled. */
@@ -719,8 +720,14 @@ static void m68k_init_arch (void);
#define PCINDEX 8 /* PC + displacement + index. */
#define ABSTOPCREL 9 /* Absolute relax down to 16-bit PC-relative. */
+/* This relaxation is required for branches where there is no long
+ branch and we are in pcrel mode. We generate a bne/beq pair. */
+#define BRANCHBWPL 10 /* Branch byte, word or pair of longs
+ */
+
/* Note that calls to frag_var need to specify the maximum expansion
- needed; this is currently 10 bytes for DBCC. */
+ needed; this is currently 12 bytes for bne/beq pair. */
+#define FRAG_VAR_SIZE 12
/* The fields are:
How far Forward this mode will reach:
@@ -780,6 +787,11 @@ relax_typeS md_relax_table[] =
{ 32767, -32768, 2, TAB (ABSTOPCREL, LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
+
+ { 127, -128, 0, TAB (BRANCHBWPL, SHORT) },
+ { 32767, -32768, 2, TAB (BRANCHBWPL, LONG) },
+ { 0, 0, 10, 0 },
+ { 1, 1, 0, 0 },
};
/* These are the machine dependent pseudo-ops. These are included so
@@ -2257,6 +2269,7 @@ m68k_ip (char *instring)
for (s = the_ins.args, opP = &the_ins.operands[0]; *s; s += 2, opP++)
{
int have_disp = 0;
+ int use_pl = 0;
/* This switch is a doozy.
Watch the first step; its a big one! */
@@ -2940,6 +2953,7 @@ m68k_ip (char *instring)
case 'b': /* Unconditional branch */
have_disp = HAVE_LONG_BRANCH (current_architecture);
+ use_pl = LONG_BRANCH_VIA_COND (current_architecture);
goto var_branch;
case 's': /* Unconditional subroutine */
@@ -3003,7 +3017,8 @@ m68k_ip (char *instring)
else
add_frag (adds (&opP->disp),
SEXT (offs (&opP->disp)),
- TAB (BRANCHBW, SZ_UNDEF));
+ (use_pl ? TAB (BRANCHBWPL, SZ_UNDEF)
+ : TAB (BRANCHBW, SZ_UNDEF)));
break;
case 'w':
if (isvar (&opP->disp))
@@ -3553,10 +3568,9 @@ reverse_8_bits (int in)
return out;
} /* reverse_8_bits() */
-/* Cause an extra frag to be generated here, inserting up to 10 bytes
- (that value is chosen in the frag_var call in md_assemble). TYPE
- is the subtype of the frag to be generated; its primary type is
- rs_machine_dependent.
+/* Cause an extra frag to be generated here, inserting up to
+ FRAG_VAR_SIZE bytes. TYPE is the subtype of the frag to be
+ generated; its primary type is rs_machine_dependent.
The TYPE parameter is also used by md_convert_frag_1 and
md_estimate_size_before_relax. The appropriate type of fixup will
@@ -4229,7 +4243,7 @@ md_assemble (char *str)
for (n = 1; n < the_ins.nfrag; n++)
wid += 2 * (the_ins.numo - the_ins.fragb[n - 1].fragoff);
/* frag_var part. */
- wid += 10;
+ wid += FRAG_VAR_SIZE;
/* Make sure the whole insn fits in one chunk, in particular that
the var part is attached, as we access one byte before the
variable frag for byte branches. */
@@ -4277,7 +4291,7 @@ md_assemble (char *str)
the_ins.reloc[m].pic_reloc));
fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
}
- (void) frag_var (rs_machine_dependent, 10, 0,
+ (void) frag_var (rs_machine_dependent, FRAG_VAR_SIZE, 0,
(relax_substateT) (the_ins.fragb[n].fragty),
the_ins.fragb[n].fadd, the_ins.fragb[n].foff, to_beg_P);
}
@@ -4849,6 +4863,7 @@ md_convert_frag_1 (fragS *fragP)
case TAB (BRABSJUNC, BYTE):
case TAB (BRABSJCOND, BYTE):
case TAB (BRANCHBW, BYTE):
+ case TAB (BRANCHBWPL, BYTE):
know (issbyte (disp));
if (disp == 0)
as_bad_where (fragP->fr_file, fragP->fr_line,
@@ -4861,6 +4876,7 @@ md_convert_frag_1 (fragS *fragP)
case TAB (BRABSJUNC, SHORT):
case TAB (BRABSJCOND, SHORT):
case TAB (BRANCHBW, SHORT):
+ case TAB (BRANCHBWPL, SHORT):
fragP->fr_opcode[1] = 0x00;
fixP = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
fragP->fr_offset, 1, RELAX_RELOC_PC16);
@@ -4872,6 +4888,24 @@ md_convert_frag_1 (fragS *fragP)
fragP->fr_offset, 1, RELAX_RELOC_PC32);
fragP->fr_fix += 4;
break;
+ case TAB (BRANCHBWPL, LONG):
+ /* Here we are converting an unconditional branch into a pair of
+ conditional branches, in order to get the range. */
+ fragP->fr_opcode[0] = 0x66; /* bne */
+ fragP->fr_opcode[1] = 0xFF;
+ fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
+ fragP->fr_offset, 1, RELAX_RELOC_PC32);
+ fixP->fx_file = fragP->fr_file;
+ fixP->fx_line = fragP->fr_line;
+ fragP->fr_fix += 4; /* Skip first offset */
+ buffer_address += 4;
+ *buffer_address++ = 0x67; /* beq */
+ *buffer_address++ = 0xff;
+ fragP->fr_fix += 2; /* Skip second branch opcode */
+ fixP = fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
+ fragP->fr_offset, 1, RELAX_RELOC_PC32);
+ fragP->fr_fix += 4;
+ break;
case TAB (BRABSJUNC, LONG):
if (fragP->fr_opcode[0] == 0x61) /* jbsr */
{
@@ -5067,6 +5101,7 @@ md_estimate_size_before_relax (fragS *fr
switch (fragP->fr_subtype)
{
case TAB (BRANCHBWL, SZ_UNDEF):
+ case TAB (BRANCHBWPL, SZ_UNDEF):
case TAB (BRABSJUNC, SZ_UNDEF):
case TAB (BRABSJCOND, SZ_UNDEF):
{
Index: gas/testsuite/gas/m68k/br-isaa.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/m68k/br-isaa.d,v
retrieving revision 1.1
diff -u -d -p -r1.1 br-isaa.d
--- gas/testsuite/gas/m68k/br-isaa.d 23 Apr 2007 07:51:27 -0000 1.1
+++ gas/testsuite/gas/m68k/br-isaa.d 27 Aug 2007 19:32:12 -0000
@@ -1,5 +1,5 @@
#name: br-isaa.d
-#objdump: -d
+#objdump: -dr
#as: -march=isaa -pcrel
.*: file format .*
@@ -10,6 +10,8 @@ Disassembly of section .text:
0: 4e71 nop
2: 60fc bras 0 <foo>
4: 6000 0000 braw 6 <foo\+0x6>
+ 6: R_68K_PC16 bar
8: 61f6 bsrs 0 <foo>
a: 6100 0000 bsrw c <foo\+0xc>
+ c: R_68K_PC16 bar
e: 4e71 nop
Index: gas/testsuite/gas/m68k/br-isab.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/m68k/br-isab.d,v
retrieving revision 1.2
diff -u -d -p -r1.2 br-isab.d
--- gas/testsuite/gas/m68k/br-isab.d 15 May 2007 09:21:24 -0000 1.2
+++ gas/testsuite/gas/m68k/br-isab.d 27 Aug 2007 19:32:12 -0000
@@ -1,5 +1,5 @@
#name: br-isab.d
-#objdump: -d
+#objdump: -dr
#as: -march=isab -pcrel
.*: file format .*
@@ -11,6 +11,8 @@ Disassembly of section .text:
2: 61ff ffff fffc bsrl 0 <foo>
8: 60f6 bras 0 <foo>
a: 60ff 0000 0000 bral c <foo\+0xc>
+ c: R_68K_PC32 bar
10: 61ee bsrs 0 <foo>
12: 61ff 0000 0000 bsrl 14 <foo\+0x14>
+ 14: R_68K_PC32 bar
18: 4e71 nop
Index: gas/testsuite/gas/m68k/br-isac.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/m68k/br-isac.d,v
retrieving revision 1.2
diff -u -d -p -r1.2 br-isac.d
--- gas/testsuite/gas/m68k/br-isac.d 15 May 2007 09:21:24 -0000 1.2
+++ gas/testsuite/gas/m68k/br-isac.d 27 Aug 2007 19:32:12 -0000
@@ -1,5 +1,5 @@
#name: br-isac.d
-#objdump: -d
+#objdump: -dr
#as: -march=isac -pcrel
.*: file format .*
@@ -10,7 +10,11 @@ Disassembly of section .text:
0: 4e71 nop
2: 61ff ffff fffc bsrl 0 <foo>
8: 60f6 bras 0 <foo>
- a: 6000 0000 braw c <foo\+0xc>
- e: 61f0 bsrs 0 <foo>
- 10: 61ff 0000 0000 bsrl 12 <foo\+0x12>
- 16: 4e71 nop
+ a: 66ff 0000 0000 bnel c <foo\+0xc>
+ c: R_68K_PC32 bar
+ 10: 67ff 0000 0000 beql 12 <foo\+0x12>
+ 12: R_68K_PC32 bar
+ 16: 61e8 bsrs 0 <foo>
+ 18: 61ff 0000 0000 bsrl 1a <foo\+0x1a>
+ 1a: R_68K_PC32 bar
+ 1e: 4e71 nop
More information about the Binutils
mailing list