* config/tc-sh.c (align_test_frag_offset_fixed_p): New.
authorKaz Kojima <kkojima@rr.iij4u.or.jp>
Sat, 14 Apr 2007 14:21:11 +0000 (14:21 +0000)
committerKaz Kojima <kkojima@rr.iij4u.or.jp>
Sat, 14 Apr 2007 14:21:11 +0000 (14:21 +0000)
(sh_optimize_expr): Likewise.
* config/tc-sh.h (md_optimize_expr): Define.
(sh_optimize_expr): Prototype.

gas/ChangeLog
gas/config/tc-sh.c
gas/config/tc-sh.h

index 4c2e52c30a1147efeb71bcc58a524578c6aff5e5..d1293f3d7d6b40fd870ab860ba249704e7d8fca8 100644 (file)
@@ -1,3 +1,10 @@
+2007-04-14  Kaz Kojima  <kkojima@rr.iij4u.or.jp>
+
+       * config/tc-sh.c (align_test_frag_offset_fixed_p): New.
+       (sh_optimize_expr): Likewise.
+       * config/tc-sh.h (md_optimize_expr): Define.
+       (sh_optimize_expr): Prototype.
+
 2007-04-06  Matt Thomas  <matt@netbsd.org>
 
        * config/tc-vax.c (vax_cons): Added to support %pcrel{8,16,32}(exp)
index 3d1ae79d76981d26bb39c9c4237ace3bdd5a02c0..6cb9c93bc450ac4a9a0102022c26315b7cf2ef81 100644 (file)
@@ -825,8 +825,91 @@ sh_elf_cons (register int nbytes)
   else
     demand_empty_rest_of_line ();
 }
+
+/* The regular frag_offset_fixed_p doesn't work for rs_align_test
+   frags.  */
+
+static bfd_boolean
+align_test_frag_offset_fixed_p (const fragS *frag1, const fragS *frag2,
+                               bfd_vma *offset)
+{
+  const fragS *frag;
+  bfd_vma off;
+
+  /* Start with offset initialised to difference between the two frags.
+     Prior to assigning frag addresses this will be zero.  */
+  off = frag1->fr_address - frag2->fr_address;
+  if (frag1 == frag2)
+    {
+      *offset = off;
+      return TRUE;
+    }
+
+  /* Maybe frag2 is after frag1.  */
+  frag = frag1;
+  while (frag->fr_type == rs_align_test)
+    {
+      off += frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag2)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  /* Maybe frag1 is after frag2.  */
+  off = frag1->fr_address - frag2->fr_address;
+  frag = frag2;
+  while (frag->fr_type == rs_align_test)
+    {
+      off -= frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag1)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
 #endif /* OBJ_ELF */
 
+/* Optimize a difference of symbols which have rs_align_test frag if
+   possible.  */
+
+int
+sh_optimize_expr (expressionS *l, operatorT op, expressionS *r)
+{
+#ifdef OBJ_ELF
+  bfd_vma frag_off;
+
+  if (op == O_subtract
+      && l->X_op == O_symbol
+      && r->X_op == O_symbol
+      && S_GET_SEGMENT (l->X_add_symbol) == S_GET_SEGMENT (r->X_add_symbol)
+      && (SEG_NORMAL (S_GET_SEGMENT (l->X_add_symbol))
+         || r->X_add_symbol == l->X_add_symbol)
+      && align_test_frag_offset_fixed_p (symbol_get_frag (l->X_add_symbol),
+                                        symbol_get_frag (r->X_add_symbol),
+                                        &frag_off))
+    {
+      l->X_add_number -= r->X_add_number;
+      l->X_add_number -= frag_off / OCTETS_PER_BYTE;
+      l->X_add_number += (S_GET_VALUE (l->X_add_symbol)
+                         - S_GET_VALUE (r->X_add_symbol));
+      l->X_op = O_constant;
+      l->X_add_symbol = 0;
+      return 1;
+    }
+#endif /* OBJ_ELF */
+  return 0;
+}
 \f
 /* This function is called once, at assembler startup time.  This should
    set up all the tables, etc that the MD part of the assembler needs.  */
index 0ad914e38b8d1a7dfe9c35ccd0f8cb5378081290..b023b488e6c92eb9b9f92dd8409c7acfcbcda99a 100644 (file)
@@ -44,6 +44,12 @@ extern int sh_small;
 #define md_cons_align(nbytes) sh_cons_align (nbytes)
 extern void sh_cons_align (int);
 
+/* We need to optimize expr with taking account of rs_align_test
+   frags.  */
+
+#define md_optimize_expr(l,o,r) sh_optimize_expr (l, o, r)
+extern int sh_optimize_expr (expressionS *, operatorT, expressionS *);
+
 /* When relaxing, we need to generate relocations for alignment
    directives.  */
 #define HANDLE_ALIGN(frag) sh_handle_align (frag)