From 0cc3409506a056370ab1f7d00c1d1e82f7e67644 Mon Sep 17 00:00:00 2001 From: Kaz Kojima Date: Sat, 14 Apr 2007 14:21:11 +0000 Subject: [PATCH] * 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. --- gas/ChangeLog | 7 ++++ gas/config/tc-sh.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ gas/config/tc-sh.h | 6 ++++ 3 files changed, 96 insertions(+) diff --git a/gas/ChangeLog b/gas/ChangeLog index 4c2e52c30a1..d1293f3d7d6 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,10 @@ +2007-04-14 Kaz Kojima + + * 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 * config/tc-vax.c (vax_cons): Added to support %pcrel{8,16,32}(exp) diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c index 3d1ae79d769..6cb9c93bc45 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. */ diff --git a/gas/config/tc-sh.h b/gas/config/tc-sh.h index 0ad914e38b8..b023b488e6c 100644 --- a/gas/config/tc-sh.h +++ b/gas/config/tc-sh.h @@ -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) -- 2.30.2