This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

bfd Patch for -relax on sh-hms


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.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]