This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
bfd Patch for -relax on sh-hms
- To: binutils at sourceware dot cygnus dot com
- Subject: bfd Patch for -relax on sh-hms
- From: Dave Brolley <brolley at redhat dot com>
- Date: Wed, 02 Feb 2000 18:44:29 -0500
- Organization: Red Hat
Hi,
This patch prevents the linker from switching the order of the
two insns in the test below when -relax is specified for the
sh-hms target. It does this by checking for interference between
both the source and target registers of each insn pair being
considered. Here is the test case
.align 2
mov r2,r1
mov.l L1,r1
L1: .long 0
If this patch is OK, could someone please commit it and let me
know. I don't have write access to binutils. Also, I'm not
subscribed to this list, so please email me directly.
Thanks,
Dave Brolley
Wed Jan 5 13:18:04 PST 2000 Toshiyasu Morita (toshi.morita@sega.com)
* coff-sh.c (USES1_REG, USES2_REG, SETS1_REG, SETS2_REG,
USESF1_REG, USESF2_REG, SETSF1_REG, SETSF2_REG): New macros.
* (sh_insn_sets_reg, sh_insn_sets_freg): New prototypes.
* (sh_insn_sets_reg, sh_insn_uses_or_sets_reg, sh_insns_sets_freg,
sh_insns_uses_or_sets_freg): New functions.
* (sh_insn_uses_regs, sh_insn_uses_freg): Use new macros.
* (sh_insns_conflict): Use new functions and new macros to
detect conflicts when two instructions both set same integer registers,
both set same fp register, and both set special register.
Index: coff-sh.c
===================================================================
RCS file: /cvs/binutils/binutils/bfd/coff-sh.c,v
retrieving revision 1.6
diff -c -r1.6 coff-sh.c
*** coff-sh.c 1999/09/07 04:28:27 1.6
--- coff-sh.c 2000/02/02 23:36:58
***************
*** 1384,1393 ****
--- 1384,1395 ----
/* This instruction uses the value in the register in the field at
mask 0x0f00 of the instruction. */
#define USES1 (0x10)
+ #define USES1_REG(x) ((x & 0x0f00) >> 8)
/* This instruction uses the value in the register in the field at
mask 0x00f0 of the instruction. */
#define USES2 (0x20)
+ #define USES2_REG(x) ((x & 0x00f0) >> 4)
/* This instruction uses the value in register 0. */
#define USESR0 (0x40)
***************
*** 1395,1404 ****
--- 1397,1408 ----
/* This instruction sets the value in the register in the field at
mask 0x0f00 of the instruction. */
#define SETS1 (0x80)
+ #define SETS1_REG(x) ((x & 0x0f00) >> 8)
/* This instruction sets the value in the register in the field at
mask 0x00f0 of the instruction. */
#define SETS2 (0x100)
+ #define SETS2_REG(x) ((x & 0x00f0) >> 4)
/* This instruction sets register 0. */
#define SETSR0 (0x200)
***************
*** 1412,1421 ****
--- 1416,1427 ----
/* This instruction uses the floating point register in the field at
mask 0x0f00 of the instruction. */
#define USESF1 (0x1000)
+ #define USESF1_REG(x) ((x & 0x0f00) >> 8)
/* This instruction uses the floating point register in the field at
mask 0x00f0 of the instruction. */
#define USESF2 (0x2000)
+ #define USESF2_REG(x) ((x & 0x00f0) >> 4)
/* This instruction uses floating point register 0. */
#define USESF0 (0x4000)
***************
*** 1423,1433 ****
--- 1429,1444 ----
/* This instruction sets the floating point register in the field at
mask 0x0f00 of the instruction. */
#define SETSF1 (0x8000)
+ #define SETSF1_REG(x) ((x & 0x0f00) >> 8)
static boolean sh_insn_uses_reg
PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));
+ static boolean sh_insn_sets_reg
+ PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));
static boolean sh_insn_uses_freg
PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));
+ static boolean sh_insn_sets_freg
+ PARAMS ((unsigned int, const struct sh_opcode *, unsigned int));
static boolean sh_insns_conflict
PARAMS ((unsigned int, const struct sh_opcode *, unsigned int,
const struct sh_opcode *));
***************
*** 1860,1865 ****
--- 1871,1890 ----
return NULL;
}
+ /* See whether an instruction uses or sets a general purpose register */
+
+ static boolean
+ sh_insn_uses_or_sets_reg (insn, op, reg)
+ unsigned int insn;
+ const struct sh_opcode *op;
+ unsigned int reg;
+ {
+ if (sh_insn_uses_reg (insn, op, reg))
+ return true;
+
+ return sh_insn_sets_reg (insn, op, reg);
+ }
+
/* See whether an instruction uses a general purpose register. */
static boolean
***************
*** 1873,1882 ****
f = op->flags;
if ((f & USES1) != 0
! && ((insn & 0x0f00) >> 8) == reg)
return true;
if ((f & USES2) != 0
! && ((insn & 0x00f0) >> 4) == reg)
return true;
if ((f & USESR0) != 0
&& reg == 0)
--- 1898,1907 ----
f = op->flags;
if ((f & USES1) != 0
! && USES1_REG (insn) == reg)
return true;
if ((f & USES2) != 0
! && USES2_REG (insn) == reg)
return true;
if ((f & USESR0) != 0
&& reg == 0)
***************
*** 1884,1889 ****
--- 1909,1952 ----
return false;
}
+ /* See whether an instruction sets a general purpose register. */
+
+ static boolean
+ sh_insn_sets_reg (insn, op, reg)
+ unsigned int insn;
+ const struct sh_opcode *op;
+ unsigned int reg;
+ {
+ unsigned int f;
+
+ f = op->flags;
+
+ if ((f & SETS1) != 0
+ && SETS1_REG (insn) == reg)
+ return true;
+ if ((f & SETS2) != 0
+ && SETS2_REG (insn) == reg)
+ return true;
+ if ((f & SETSR0) != 0
+ && reg == 0)
+ return true;
+
+ return false;
+ }
+
+ /* See whether an instruction uses or sets a floating point register */
+
+ static boolean
+ sh_insn_uses_or_sets_freg (insn, op, reg)
+ unsigned int insn;
+ const struct sh_opcode *op;
+ unsigned int reg;
+ {
+ if (sh_insn_uses_freg (insn, op, reg))
+ return true;
+
+ return sh_insn_sets_freg (insn, op, reg);
+ }
/* See whether an instruction uses a floating point register. */
***************
*** 1907,1916 ****
bit of the register number. */
if ((f & USESF1) != 0
! && ((insn & 0x0e00) >> 8) == (freg & 0xe))
return true;
if ((f & USESF2) != 0
! && ((insn & 0x00e0) >> 4) == (freg & 0xe))
return true;
if ((f & USESF0) != 0
&& freg == 0)
--- 1970,1979 ----
bit of the register number. */
if ((f & USESF1) != 0
! && (USESF1_REG (insn) & 0xe) == (freg & 0xe))
return true;
if ((f & USESF2) != 0
! && (USESF2_REG (insn) & 0xe) == (freg & 0xe))
return true;
if ((f & USESF0) != 0
&& freg == 0)
***************
*** 1919,1924 ****
--- 1982,2015 ----
return false;
}
+ /* See whether an instruction sets a floating point register. */
+
+ static boolean
+ sh_insn_sets_freg (insn, op, freg)
+ unsigned int insn;
+ const struct sh_opcode *op;
+ unsigned int freg;
+ {
+ unsigned int f;
+
+ f = op->flags;
+
+ /* We can't tell if this is a double-precision insn, so just play safe
+ and assume that it might be. So not only have we test FREG against
+ itself, but also even FREG against FREG+1 - if the using insn uses
+ just the low part of a double precision value - but also an odd
+ FREG against FREG-1 - if the setting insn sets just the low part
+ of a double precision value.
+ So what this all boils down to is that we have to ignore the lowest
+ bit of the register number. */
+
+ if ((f & SETSF1) != 0
+ && (SETSF1_REG (insn) & 0xe) == (freg & 0xe))
+ return true;
+
+ return false;
+ }
+
/* See whether instructions I1 and I2 conflict, assuming I1 comes
before I2. OP1 and OP2 are the corresponding sh_opcode structures.
This should return true if there is a conflict, or false if the
***************
*** 1946,1980 ****
|| (f2 & (BRANCH | DELAY)) != 0)
return true;
! if ((f1 & SETSSP) != 0 && (f2 & USESSP) != 0)
! return true;
! if ((f2 & SETSSP) != 0 && (f1 & USESSP) != 0)
return true;
if ((f1 & SETS1) != 0
! && sh_insn_uses_reg (i2, op2, (i1 & 0x0f00) >> 8))
return true;
if ((f1 & SETS2) != 0
! && sh_insn_uses_reg (i2, op2, (i1 & 0x00f0) >> 4))
return true;
if ((f1 & SETSR0) != 0
! && sh_insn_uses_reg (i2, op2, 0))
return true;
if ((f1 & SETSF1) != 0
! && sh_insn_uses_freg (i2, op2, (i1 & 0x0f00) >> 8))
return true;
if ((f2 & SETS1) != 0
! && sh_insn_uses_reg (i1, op1, (i2 & 0x0f00) >> 8))
return true;
if ((f2 & SETS2) != 0
! && sh_insn_uses_reg (i1, op1, (i2 & 0x00f0) >> 4))
return true;
if ((f2 & SETSR0) != 0
! && sh_insn_uses_reg (i1, op1, 0))
return true;
if ((f2 & SETSF1) != 0
! && sh_insn_uses_freg (i1, op1, (i2 & 0x0f00) >> 8))
return true;
/* The instructions do not conflict. */
--- 2037,2070 ----
|| (f2 & (BRANCH | DELAY)) != 0)
return true;
! if ((f1 & (SETSSP | USESSP)) &&
! (f2 & (SETSSP | USESSP)))
return true;
if ((f1 & SETS1) != 0
! && sh_insn_uses_or_sets_reg (i2, op2, SETS1_REG (i1)))
return true;
if ((f1 & SETS2) != 0
! && sh_insn_uses_or_sets_reg (i2, op2, SETS2_REG (i1)))
return true;
if ((f1 & SETSR0) != 0
! && sh_insn_uses_or_sets_reg (i2, op2, 0))
return true;
if ((f1 & SETSF1) != 0
! && sh_insn_uses_or_sets_freg (i2, op2, SETSF1_REG (i1)))
return true;
if ((f2 & SETS1) != 0
! && sh_insn_uses_or_sets_reg (i1, op1, SETS1_REG (i2)))
return true;
if ((f2 & SETS2) != 0
! && sh_insn_uses_or_sets_reg (i1, op1, SETS2_REG (i2)))
return true;
if ((f2 & SETSR0) != 0
! && sh_insn_uses_or_sets_reg (i1, op1, 0))
return true;
if ((f2 & SETSF1) != 0
! && sh_insn_uses_or_sets_freg (i1, op1, SETSF1_REG (i2)))
return true;
/* The instructions do not conflict. */