From: Doug Evans Date: Thu, 7 May 1998 09:31:42 +0000 (+0000) Subject: * cgen.h: New file. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=defc70bf2bffe18595ee6047d7440b9d79933564;p=binutils-gdb.git * cgen.h: New file. * cgen.c: Include it. (MAX_FIXUPS): Renamed to CGEN_MAX_FIXUPS. (cgen_asm_finish_insn): Result is now void. New arg `result'. All callers updated. * config/tc-m32r.c: Include cgen.h. (m23r_insn): New members num_fixups,fixups. (assemble_parallel_insn): Initialize debug_sym_link for each insn. (md_assemble): Simplify code to pack two insns in parallel. When swapping two insns, update their fixups. --- diff --git a/gas/.Sanitize b/gas/.Sanitize index b51684ef3d9..344d4b7fd3f 100644 --- a/gas/.Sanitize +++ b/gas/.Sanitize @@ -51,6 +51,7 @@ bignum-copy.c bignum.h bit_fix.h cgen.c +cgen.h cond.c config config-gas.com diff --git a/gas/ChangeLog b/gas/ChangeLog index e3df01e4057..22b3e6051d1 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,18 @@ +Thu May 7 02:19:14 1998 Doug Evans + + * cgen.h: New file. + * cgen.c: Include it. + (MAX_FIXUPS): Renamed to CGEN_MAX_FIXUPS. + (cgen_asm_finish_insn): Result is now void. New arg `result'. + All callers updated. + * config/tc-m32r.c: Include cgen.h. + (m23r_insn): New members num_fixups,fixups. +start-sanitize-m32rx + (assemble_parallel_insn): Initialize debug_sym_link for each insn. + (md_assemble): Simplify code to pack two insns in parallel. + When swapping two insns, update their fixups. +end-sanitize-m32rx + start-sanitize-sky Wed May 6 16:26:57 1998 Doug Evans diff --git a/gas/cgen.c b/gas/cgen.c index 3e1885ec126..e9954a1a589 100644 --- a/gas/cgen.c +++ b/gas/cgen.c @@ -24,6 +24,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "cgen-opc.h" #include "as.h" #include "subsegs.h" +#include "cgen.h" /* Callback to insert a register into the symbol table. A target may choose to let GAS parse the registers. @@ -32,7 +33,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void cgen_asm_record_register (name, number) char * name; - int number; + int number; { /* Use symbol_create here instead of symbol_new so we don't try to output registers into the object file's symbol table. */ @@ -53,15 +54,13 @@ cgen_asm_record_register (name, number) struct fixup { - int opindex; - int opinfo; + int opindex; + int opinfo; expressionS exp; }; -#define MAX_FIXUPS 5 - -static struct fixup fixups [MAX_FIXUPS]; -static int num_fixups; +static struct fixup fixups [CGEN_MAX_FIXUPS]; +static int num_fixups; /* Prepare to parse an instruction. ??? May wish to make this static and delete calls in md_assemble. */ @@ -80,7 +79,7 @@ cgen_queue_fixup (opindex, opinfo, expP) expressionS * expP; { /* We need to generate a fixup for this expression. */ - if (num_fixups >= MAX_FIXUPS) + if (num_fixups >= CGEN_MAX_FIXUPS) as_fatal (_("too many fixups")); fixups[num_fixups].exp = * expP; fixups[num_fixups].opindex = opindex; @@ -92,8 +91,8 @@ cgen_queue_fixup (opindex, opinfo, expP) and to have this backup be swapped with the current chain. This allows certain ports, eg the m32r, to swap two instructions and swap their fixups at the same time. */ -static struct fixup saved_fixups [MAX_FIXUPS]; -static int saved_num_fixups; +static struct fixup saved_fixups [CGEN_MAX_FIXUPS]; +static int saved_num_fixups; void cgen_save_fixups () @@ -118,7 +117,7 @@ cgen_restore_fixups () void cgen_swap_fixups () { - int tmp; + int tmp; struct fixup tmp_fixup; if (num_fixups == 0) @@ -135,7 +134,7 @@ cgen_swap_fixups () saved_num_fixups = num_fixups; num_fixups = tmp; - for (tmp = MAX_FIXUPS; tmp--;) + for (tmp = CGEN_MAX_FIXUPS; tmp--;) { tmp_fixup = saved_fixups [tmp]; saved_fixups [tmp] = fixups [tmp]; @@ -235,23 +234,23 @@ static jmp_buf expr_jmp_buf; const char * cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP) - enum cgen_parse_operand_type want; - const char ** strP; - int opindex; - int opinfo; + enum cgen_parse_operand_type want; + const char ** strP; + int opindex; + int opinfo; enum cgen_parse_operand_result * resultP; - bfd_vma * valueP; + bfd_vma * valueP; { #ifdef __STDC__ - /* These is volatile to survive the setjmp. */ - char * volatile hold; + /* These are volatile to survive the setjmp. */ + char * volatile hold; enum cgen_parse_operand_result * volatile resultP_1; #else - static char * hold; - static enum cgen_parse_operand_result * resultP_1; + static char * hold; + static enum cgen_parse_operand_result * resultP_1; #endif - const char * errmsg = NULL; - expressionS exp; + const char * errmsg = NULL; + expressionS exp; if (want == CGEN_PARSE_OPERAND_INIT) { @@ -322,18 +321,23 @@ cgen_md_operand (expressionP) /* Finish assembling instruction INSN. BUF contains what we've built up so far. LENGTH is the size of the insn in bits. + RELAX_P is non-zero if relaxable insns should be emitted as such. + Otherwise they're emitted in non-relaxable forms. + The "result" is stored in RESULT if non-NULL. Returns the address of the buffer containing the assembled instruction, in case the caller needs to modify it for some reason. */ -char * -cgen_asm_finish_insn (insn, buf, length) +void +cgen_asm_finish_insn (insn, buf, length, relax_p, result) const CGEN_INSN * insn; - cgen_insn_t * buf; - unsigned int length; + cgen_insn_t * buf; + unsigned int length; + int relax_p; + finished_insn * result; { - int i; - int relax_operand; - char * f; + int i; + int relax_operand; + char * f; unsigned int byte_len = length / 8; /* ??? Target foo issues various warnings here, so one might want to provide @@ -354,7 +358,7 @@ cgen_asm_finish_insn (insn, buf, length) /* Is there a relaxable insn with the relaxable operand needing a fixup? */ relax_operand = -1; - if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0) + if (relax_p && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0) { /* Scan the fixups for the operand affected by relaxing (i.e. the branch address). */ @@ -372,7 +376,7 @@ cgen_asm_finish_insn (insn, buf, length) if (relax_operand != -1) { - int max_len; + int max_len; fragS * old_frag; #ifdef TC_CGEN_MAX_RELAX @@ -405,9 +409,15 @@ cgen_asm_finish_insn (insn, buf, length) old_frag->fr_cgen.insn = insn; old_frag->fr_cgen.opindex = fixups[relax_operand].opindex; old_frag->fr_cgen.opinfo = fixups[relax_operand].opinfo; + if (result) + result->frag = old_frag; } else - f = frag_more (byte_len); + { + f = frag_more (byte_len); + if (result) + result->frag = frag_now; + } /* If we're recording insns as numbers (rather than a string of bytes), target byte order handling is deferred until now. */ @@ -436,10 +446,13 @@ cgen_asm_finish_insn (insn, buf, length) /* Create any fixups. */ for (i = 0; i < num_fixups; ++i) { + fixS * fixP; + /* Don't create fixups for these. That's done during relaxation. We don't need to test for CGEN_INSN_RELAX as they can't get here (see above). */ - if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0 + if (relax_p + && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAXABLE) != 0 && CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex], CGEN_OPERAND_RELAX) != 0) continue; @@ -448,14 +461,20 @@ cgen_asm_finish_insn (insn, buf, length) #define md_cgen_record_fixup_exp cgen_record_fixup_exp #endif - md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal, - insn, length, - & CGEN_SYM (operand_table) [fixups[i].opindex], - fixups[i].opinfo, - & fixups[i].exp); + fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal, + insn, length, + & CGEN_SYM (operand_table) [fixups[i].opindex], + fixups[i].opinfo, + & fixups[i].exp); + if (result) + result->fixups[i] = fixP; } - return f; + if (result) + { + result->num_fixups = num_fixups; + result->addr = f; + } } /* Apply a fixup to the object code. This is called for all the diff --git a/gas/config/tc-m32r.c b/gas/config/tc-m32r.c index aee758336d0..31c491587d3 100644 --- a/gas/config/tc-m32r.c +++ b/gas/config/tc-m32r.c @@ -24,7 +24,18 @@ #include "subsegs.h" #include "symcat.h" #include "cgen-opc.h" +#include "cgen.h" +/* Linked list of symbols that are debugging symbols to be defined as the + beginning of the current instruction. */ +typedef struct sym_link +{ + struct sym_link *next; + symbolS *symbol; +} sym_linkS; + +static sym_linkS *debug_sym_link = (sym_linkS *)0; + /* Structure to hold all of the different components describing an individual instruction. */ typedef struct { @@ -38,7 +49,10 @@ typedef struct #endif char * addr; fragS * frag; + int num_fixups; + fixS * fixups [CGEN_MAX_FIXUPS]; int indices [MAX_OPERAND_INSTANCES]; + sym_linkS *debug_sym_link; } m32r_insn; @@ -69,10 +83,8 @@ static int enable_m32rx = 0; instruction might have constraint violations. */ static int warn_explicit_parallel_conflicts = 1; -/* start-sanitize-phase2-m32rx */ /* Non-zero if insns can be made parallel. */ static int optimize; -/* end-sanitize-phase2-m32rx */ /* end-sanitize-m32rx */ /* stuff for .scomm symbols. */ @@ -124,10 +136,10 @@ allow_m32rx (on) /* end-sanitize-m32rx */ #define M32R_SHORTOPTS "" -/* start-sanitize-phase2-m32rx */ +/* start-sanitize-m32rx */ #undef M32R_SHORTOPTS #define M32R_SHORTOPTS "O" -/* end-sanitize-phase2-m32rx */ +/* end-sanitize-m32rx */ const char * md_shortopts = M32R_SHORTOPTS; struct option md_longopts[] = @@ -162,11 +174,9 @@ md_parse_option (c, arg) switch (c) { /* start-sanitize-m32rx */ -/* start-sanitize-phase2-m32rx */ case 'O': optimize = 1; break; -/* end-sanitize-phase2-m32rx */ case OPTION_M32RX: allow_m32rx (1); @@ -204,10 +214,8 @@ md_show_usage (stream) fprintf (stream, _("\ --m32rx support the extended m32rx instruction set\n")); -/* start-sanitize-phase2-m32rx */ fprintf (stream, _("\ -O try to combine instructions in parallel\n")); -/* end-sanitize-phase2-m32rx */ fprintf (stream, _("\ --warn-explicit-parallel-conflicts warn when parallel instrucitons violate contraints\n")); @@ -229,6 +237,8 @@ md_show_usage (stream) static void fill_insn PARAMS ((int)); static void m32r_scomm PARAMS ((int)); +static void debug_sym PARAMS ((int)); +static void expand_debug_syms PARAMS ((sym_linkS *, int)); /* Set by md_assemble for use by m32r_fill_insn. */ static subsegT prev_subseg; @@ -237,12 +247,13 @@ static segT prev_seg; /* The target specific pseudo-ops which we support. */ const pseudo_typeS md_pseudo_table[] = { - { "word", cons, 4 }, - { "fillinsn", fill_insn, 0 }, - { "scomm", m32r_scomm, 0 }, + { "word", cons, 4 }, + { "fillinsn", fill_insn, 0 }, + { "scomm", m32r_scomm, 0 }, + { "debugsym", debug_sym, 0 }, /* start-sanitize-m32rx */ - { "m32r", allow_m32rx, 0}, - { "m32rx", allow_m32rx, 1}, + { "m32r", allow_m32rx, 0 }, + { "m32rx", allow_m32rx, 1 }, /* end-sanitize-m32rx */ { NULL, NULL, 0 } }; @@ -324,6 +335,77 @@ fill_insn (ignore) seen_relaxable_p = 0; } +/* Record the symbol so that when we output the insn, we can create + a symbol that is at the start of the instruction. This is used + to emit the label for the start of a breakpoint without causing + the assembler to emit a NOP if the previous instruction was a + 16 bit instruction. */ + +static void +debug_sym (ignore) + int ignore; +{ + register char *name; + register char delim; + register char *end_name; + register symbolS *symbolP; + register sym_linkS *link; + + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + + if ((symbolP = symbol_find (name)) == NULL + && (symbolP = md_undefined_symbol (name)) == NULL) + { + symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag); + } + + symbol_table_insert (symbolP); + if (S_IS_DEFINED (symbolP) && S_GET_SEGMENT (symbolP) != reg_section) + as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP)); + + else + { + link = (sym_linkS *) xmalloc (sizeof (sym_linkS)); + link->symbol = symbolP; + link->next = debug_sym_link; + debug_sym_link = link; + symbolP->local = 1; + } + + *end_name = delim; + demand_empty_rest_of_line (); +} + +/* Second pass to expanding the debug symbols, go through linked + list of symbols and reassign the address. */ + +static void +expand_debug_syms (syms, align) + sym_linkS *syms; + int align; +{ + char *save_input_line = input_line_pointer; + sym_linkS *next_syms; + expressionS exp; + + if (!syms) + return; + + (void) m32r_do_align (align, NULL, 0, 0); + for (; syms != (sym_linkS *)0; syms = next_syms) + { + symbolS *symbolP = syms->symbol; + next_syms = syms->next; + input_line_pointer = ".\n"; + pseudo_set (symbolP); + free ((char *)syms); + } + + input_line_pointer = save_input_line; +} + /* Cover function to fill_insn called after a label and at end of assembly. The result is always 1: we're called in a conditional to see if the @@ -608,6 +690,9 @@ assemble_parallel_insn (str, str2) if (prev_insn.insn) fill_insn (0); + first.debug_sym_link = debug_sym_link; + debug_sym_link = (sym_linkS *)0; + /* Parse the first instruction. */ if (! (first.insn = CGEN_SYM (assemble_insn) (str, & first.fields, first.buffer, & errmsg))) @@ -656,6 +741,8 @@ assemble_parallel_insn (str, str2) if (first.insn == NULL) as_fatal (_("internal error: m32r_cgen_lookup_get_insn_operands failed for first insn")); + second.debug_sym_link = NULL; + /* Parse the second instruction. */ if (! (second.insn = CGEN_SYM (assemble_insn) (str, & second.fields, second.buffer, & errmsg))) @@ -721,8 +808,9 @@ assemble_parallel_insn (str, str2) cgen_swap_fixups (); /* Write it out. */ - (void) cgen_asm_finish_insn (first.orig_insn, first.buffer, - CGEN_FIELDS_BITSIZE (& first.fields), 0); + expand_debug_syms (first.debug_sym_link, 1); + cgen_asm_finish_insn (first.orig_insn, first.buffer, + CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL); /* Force the top bit of the second insn to be set. */ make_parallel (second.buffer); @@ -731,15 +819,17 @@ assemble_parallel_insn (str, str2) cgen_restore_fixups (); /* Write it out. */ - (void) cgen_asm_finish_insn (second.orig_insn, second.buffer, - CGEN_FIELDS_BITSIZE (& second.fields), 0); + expand_debug_syms (second.debug_sym_link, 1); + cgen_asm_finish_insn (second.orig_insn, second.buffer, + CGEN_FIELDS_BITSIZE (& second.fields), 0, NULL); } /* Try swapping the instructions to see if they work that way. */ else if (can_make_parallel (& second, & first) == NULL) { /* Write out the second instruction first. */ - (void) cgen_asm_finish_insn (second.orig_insn, second.buffer, - CGEN_FIELDS_BITSIZE (& second.fields), 0); + expand_debug_syms (second.debug_sym_link, 1); + cgen_asm_finish_insn (second.orig_insn, second.buffer, + CGEN_FIELDS_BITSIZE (& second.fields), 0, NULL); /* Force the top bit of the first instruction to be set. */ make_parallel (first.buffer); @@ -748,8 +838,9 @@ assemble_parallel_insn (str, str2) cgen_restore_fixups (); /* Write out the first instruction. */ - (void) cgen_asm_finish_insn (first.orig_insn, first.buffer, - CGEN_FIELDS_BITSIZE (& first.fields), 0); + expand_debug_syms (first.debug_sym_link, 1); + cgen_asm_finish_insn (first.orig_insn, first.buffer, + CGEN_FIELDS_BITSIZE (& first.fields), 0, NULL); } else { @@ -785,6 +876,9 @@ md_assemble (str) } /* end-sanitize-m32rx */ + insn.debug_sym_link = debug_sym_link; + debug_sym_link = (sym_linkS *)0; + insn.insn = CGEN_SYM (assemble_insn) (str, & insn.fields, insn.buffer, & errmsg); if (!insn.insn) { @@ -810,26 +904,28 @@ md_assemble (str) fill_insn (0); } + expand_debug_syms (insn.debug_sym_link, 2); + /* Doesn't really matter what we pass for RELAX_P here. */ - (void) cgen_asm_finish_insn (insn.insn, insn.buffer, - CGEN_FIELDS_BITSIZE (& insn.fields), 1); + cgen_asm_finish_insn (insn.insn, insn.buffer, + CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); } else { + int on_32bit_boundary_p; /* start-sanitize-m32rx */ -/* start-sanitize-phase2-m32rx */ int swap = false; -/* end-sanitize-phase2-m32rx */ /* end-sanitize-m32rx */ if (CGEN_INSN_BITSIZE (insn.insn) != 16) abort(); + insn.orig_insn = insn.insn; +/* start-sanitize-m32rx */ if (enable_m32rx) { /* Get the indices of the operands of the instruction. FIXME: See assemble_parallel for notes on orig_insn. */ - insn.orig_insn = insn.insn; insn.insn = m32r_cgen_lookup_get_insn_operands (NULL, bfd_getb16 ((char *) insn.buffer), 16, @@ -837,58 +933,61 @@ md_assemble (str) if (insn.insn == NULL) as_fatal (_("internal error: m32r_cgen_get_insn_operands failed")); } - else - insn.orig_insn = insn.insn; +/* end-sanitize-m32rx */ - /* Keep track of whether we've seen a pair of 16 bit insns. + /* Compute whether we're on a 32 bit boundary or not. prev_insn.insn is NULL when we're on a 32 bit boundary. */ - if (prev_insn.insn) - { -/* start-sanitize-m32rx */ -/* start-sanitize-phase2-m32rx */ - /* Look to see if this instruction can be combined with the - previous instruction to make one, parallel, 32 bit instruction. - If the previous instruction (potentially) changed the flow of - program control, then it cannot be combined with the current - instruction. If the current instruction is relaxable, then it - might be replaced with a longer version, so we cannot combine it. - Also if the output of the previous instruction is used as an - input to the current instruction then it cannot be combined. - Otherwise call can_make_parallel() with both orderings of the - instructions to see if they can be combined. */ - if ( enable_m32rx - && optimize - && CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0 - && ! writes_to_pc (& prev_insn) - && ! first_writes_to_seconds_operands (& prev_insn, &insn, false) - ) - { - if (can_make_parallel (& prev_insn, & insn) == NULL) - make_parallel (insn.buffer); - else if (can_make_parallel (& insn, & prev_insn) == NULL) - swap = true; - } -/* end-sanitize-phase2-m32rx */ -/* end-sanitize-m32rx */ + on_32bit_boundary_p = prev_insn.insn == NULL; - prev_insn.insn = NULL; - } - else +/* start-sanitize-m32rx */ + /* Look to see if this instruction can be combined with the + previous instruction to make one, parallel, 32 bit instruction. + If the previous instruction (potentially) changed the flow of + program control, then it cannot be combined with the current + instruction. If the current instruction is relaxable, then it + might be replaced with a longer version, so we cannot combine it. + Also if the output of the previous instruction is used as an + input to the current instruction then it cannot be combined. + Otherwise call can_make_parallel() with both orderings of the + instructions to see if they can be combined. */ + if ( ! on_32bit_boundary_p + && enable_m32rx + && optimize + && CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_RELAXABLE) == 0 + && ! writes_to_pc (& prev_insn) + && ! first_writes_to_seconds_operands (& prev_insn, &insn, false) + ) { - prev_insn = insn; + if (can_make_parallel (& prev_insn, & insn) == NULL) + make_parallel (insn.buffer); + else if (can_make_parallel (& insn, & prev_insn) == NULL) + swap = true; } +/* end-sanitize-m32rx */ + + expand_debug_syms (insn.debug_sym_link, 1); - /* Record the frag that might be used by this insn. */ - insn.frag = frag_now; - insn.addr = cgen_asm_finish_insn (insn.orig_insn, insn.buffer, - CGEN_FIELDS_BITSIZE (& insn.fields), - 1 /*relax_p*/); + { + int i; + finished_insnS fi; + + /* Ensure each pair of 16 bit insns is in the same frag. */ + frag_grow (4); + + cgen_asm_finish_insn (insn.orig_insn, insn.buffer, + CGEN_FIELDS_BITSIZE (& insn.fields), + 1 /*relax_p*/, &fi); + insn.addr = fi.addr; + insn.frag = fi.frag; + insn.num_fixups = fi.num_fixups; + for (i = 0; i < fi.num_fixups; ++i) + insn.fixups[i] = fi.fixups[i]; + } /* start-sanitize-m32rx */ -/* start-sanitize-phase2-m32rx */ if (swap) { - int tmp; + int i,tmp; #define SWAP_BYTES(a,b) tmp = a; a = b; b = tmp @@ -899,21 +998,32 @@ md_assemble (str) make_parallel (insn.addr); /* Swap any relaxable frags recorded for the two insns. */ + /* FIXME: Clarify. relaxation precludes parallel insns */ if (prev_insn.frag->fr_opcode == prev_insn.addr) prev_insn.frag->fr_opcode = insn.addr; else if (insn.frag->fr_opcode == insn.addr) insn.frag->fr_opcode = prev_insn.addr; - } -/* end-sanitize-phase2-m32rx */ - /* Record where this instruction was assembled. */ - prev_insn.addr = insn.addr; - prev_insn.frag = insn.frag; + /* Update the addresses in any fixups. + Note that we don't have to handle the case where each insn is in + a different frag as we ensure they're in the same frag above. */ + for (i = 0; i < prev_insn.num_fixups; ++i) + prev_insn.fixups[i]->fx_where += 2; + for (i = 0; i < insn.num_fixups; ++i) + insn.fixups[i]->fx_where -= 2; + } /* end-sanitize-m32rx */ + + /* Keep track of whether we've seen a pair of 16 bit insns. + prev_insn.insn is NULL when we're on a 32 bit boundary. */ + if (on_32bit_boundary_p) + prev_insn = insn; + else + prev_insn.insn = NULL; /* If the insn needs the following one to be on a 32 bit boundary (e.g. subroutine calls), fill this insn's slot. */ - if (prev_insn.insn != NULL + if (on_32bit_boundary_p && CGEN_INSN_ATTR (insn.orig_insn, CGEN_INSN_FILL_SLOT) != 0) fill_insn (0);