aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-sh.c
diff options
context:
space:
mode:
authorKaz Kojima <kkojima@rr.iij4u.or.jp>2007-04-14 14:21:11 +0000
committerKaz Kojima <kkojima@rr.iij4u.or.jp>2007-04-14 14:21:11 +0000
commit0cc3409506a056370ab1f7d00c1d1e82f7e67644 (patch)
tree081a67dd9bc7bd47fa3e9a7a27f2a553fc0ac7c6 /gas/config/tc-sh.c
parent3fcd97f16cb46d4c493e892f85a188969e0a95e7 (diff)
downloadgdb-0cc3409506a056370ab1f7d00c1d1e82f7e67644.zip
gdb-0cc3409506a056370ab1f7d00c1d1e82f7e67644.tar.gz
gdb-0cc3409506a056370ab1f7d00c1d1e82f7e67644.tar.bz2
* 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.
Diffstat (limited to 'gas/config/tc-sh.c')
-rw-r--r--gas/config/tc-sh.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index 3d1ae79..6cb9c93 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -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;
+}
/* 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. */