From 0a44c2b16f06f5f84edf9cd3aeca67b764403fe8 Mon Sep 17 00:00:00 2001 From: Donald Lindsay Date: Thu, 25 May 2000 22:35:05 +0000 Subject: [PATCH] New short-conditional-branch packing rules for D10V. --- gas/ChangeLog | 9 +++ gas/config/tc-d10v.c | 130 ++++++++++++++++++++++++++++--------------- 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 74faad15fe2..39a43ed3a37 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +Thu May 4 15:27:07 2000 Donald Lindsay + + * config/tc-d10v.c (write_2_short, parallel_ok, md_assemble, + d10v_cleanup) implement Mitsubishi's newly explained branch-packing + rules, with warning when a GAS statement specifies a packing that + will result in an instruction being squashed. + Added typdef packing_type and enumerals, changed various integer literals + to use the enumerals. + 2000-05-24 David Mosberger * config/tc-ia64.c (dot_restorereg_p): New function. diff --git a/gas/config/tc-d10v.c b/gas/config/tc-d10v.c index 83a855c59d5..268f9517ec8 100644 --- a/gas/config/tc-d10v.c +++ b/gas/config/tc-d10v.c @@ -64,6 +64,13 @@ static Fixups *fixups; static int do_not_ignore_hash = 0; +typedef int packing_type; +#define PACK_UNSPEC (0) /* packing order not specified */ +#define PACK_PARALLEL (1) /* "||" */ +#define PACK_LEFT_RIGHT (2) /* "->" */ +#define PACK_RIGHT_LEFT (3) /* "<-" */ +static packing_type etype = PACK_UNSPEC; /* used by d10v_cleanup */ + /* True if instruction swapping warnings should be inhibited. */ static unsigned char flag_warn_suppress_instructionswap; /* --nowarnswap */ @@ -79,13 +86,13 @@ static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS static void write_long PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx)); static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx)); static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1, - struct d10v_opcode *opcode2, unsigned long insn2, int exec_type, Fixups *fx)); + struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type, Fixups *fx)); static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode)); static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type, offsetT value, int left, fixS *fix)); static int parallel_ok PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1, struct d10v_opcode *opcode2, unsigned long insn2, - int exec_type)); + packing_type exec_type)); static symbolS * find_symbol_matching_register PARAMS ((expressionS *)); struct option md_longopts[] = @@ -724,38 +731,40 @@ write_1_short (opcode, insn, fx) fx->fc = 0; } -/* write out a short form instruction if possible */ -/* return number of instructions not written out */ +/* Expects two short instructions. + If possible, writes out both as a single packed instruction. + Otherwise, writes out the first one, packed with a NOP. + Returns number of instructions not written out. */ + static int write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) struct d10v_opcode *opcode1, *opcode2; unsigned long insn1, insn2; - int exec_type; + packing_type exec_type; Fixups *fx; { unsigned long insn; char *f; int i,j, where; - if ( (exec_type != 1) && ((opcode1->exec_type & PARONLY) + if ( (exec_type != PACK_PARALLEL) && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY))) as_fatal (_("Instruction must be executed in parallel")); if ( (opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE)) as_fatal (_("Long instructions may not be combined.")); - if(opcode1->exec_type & BRANCH_LINK && exec_type == 0) - { - /* Instructions paired with a subroutine call are executed before the - subroutine, so don't do these pairings unless explicitly requested. */ - write_1_short (opcode1, insn1, fx->next); - return (1); - } switch (exec_type) { - case 0: /* order not specified */ - if ( Optimizing && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)) + case PACK_UNSPEC: /* order not specified */ + if (opcode1->exec_type & ALONE) + { + /* Case of a short branch on a separate GAS line. Pack with NOP. */ + write_1_short (opcode1, insn1, fx->next); + return 1; + } + if (Optimizing && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)) { /* parallel */ if (opcode1->unit == IU) @@ -765,25 +774,27 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) else { insn = FM00 | (insn1 << 15) | insn2; + /* Advance over dummy fixup since packed insn1 in L */ fx = fx->next; } } else if (opcode1->unit == IU) - { - /* reverse sequential */ - insn = FM10 | (insn2 << 15) | insn1; - } + /* reverse sequential with IU opcode1 on right and done first */ + insn = FM10 | (insn2 << 15) | insn1; else { - /* sequential */ + /* sequential with non-IU opcode1 on left and done first */ insn = FM01 | (insn1 << 15) | insn2; - fx = fx->next; + /* Advance over dummy fixup since packed insn1 in L */ + fx = fx->next; } break; - case 1: /* parallel */ - if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ) - as_fatal (_("One of these instructions may not be executed in parallel.")); + + case PACK_PARALLEL: + if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ) + as_fatal + (_("One of these instructions may not be executed in parallel.")); if (opcode1->unit == IU) { if (opcode2->unit == IU) @@ -803,23 +814,31 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) else { insn = FM00 | (insn1 << 15) | insn2; + /* Advance over dummy fixup since packed insn1 in L */ fx = fx->next; } break; - case 2: /* sequential */ + + + case PACK_LEFT_RIGHT: if (opcode1->unit != IU) insn = FM01 | (insn1 << 15) | insn2; else if (opcode2->unit == MU || opcode2->unit == EITHER) { if (!flag_warn_suppress_instructionswap) as_warn (_("Swapping instruction order")); - insn = FM10 | (insn2 << 15) | insn1; + insn = FM10 | (insn2 << 15) | insn1; } else as_fatal (_("IU instruction may not be in the left container")); + if (opcode1->exec_type & ALONE) + as_warn (_("Instruction in R container is squashed by flow control instruction in L container.")); + /* Advance over dummy fixup */ fx = fx->next; break; - case 3: /* reverse sequential */ + + + case PACK_RIGHT_LEFT: if (opcode2->unit != MU) insn = FM10 | (insn1 << 15) | insn2; else if (opcode1->unit == IU || opcode1->unit == EITHER) @@ -830,15 +849,29 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) } else as_fatal (_("MU instruction may not be in the right container")); + if (opcode2->exec_type & ALONE) + as_warn (_("Instruction in R container is squashed by flow control instruction in L container.")); + /* Advance over dummy fixup */ fx = fx->next; break; + + default: as_fatal (_("unknown execution type passed to write_2_short()")); } + f = frag_more(4); number_to_chars_bigendian (f, insn, 4); + /* Process fixup chains. + Note that the packing code above advanced fx conditionally. + dlindsay@cygnus.com: There's something subtle going on here involving + _dummy_first_bfd_reloc_code_real. This is related to the + difference between BFD_RELOC_D10V_10_PCREL_R and _L, ie whether + a fixup is done in the L or R container. A bug in this code + can pass Plum Hall fine, yet still affect hand-written assembler. */ + for (j=0; j<2; j++) { for (i=0; i < fx->fc; i++) @@ -876,7 +909,7 @@ static int parallel_ok (op1, insn1, op2, insn2, exec_type) struct d10v_opcode *op1, *op2; unsigned long insn1, insn2; - int exec_type; + packing_type exec_type; { int i, j, flags, mask, shift, regno; unsigned long ins, mod[2], used[2]; @@ -889,9 +922,10 @@ parallel_ok (op1, insn1, op2, insn2, exec_type) || (op1->unit == MU && op2->unit == MU)) return 0; - /* If the first instruction is a branch and this is auto parallazation, - don't combine with any second instruction. */ - if (exec_type == 0 && (op1->exec_type & BRANCH) != 0) + /* If this is auto parallization, and either instruction is a branch, + don't parallel. */ + if (exec_type == PACK_UNSPEC + && (op1->exec_type & ALONE || op2->exec_type & ALONE)) return 0; /* The idea here is to create two sets of bitmasks (mod and used) @@ -1005,33 +1039,35 @@ static unsigned long prev_insn; static struct d10v_opcode *prev_opcode = 0; static subsegT prev_subseg; static segT prev_seg = 0;; -static int etype = 0; /* saved extype. used for multiline instructions */ void md_assemble (str) char *str; { + /* etype is saved extype. for multiline instructions */ + + packing_type extype = PACK_UNSPEC; /* parallel, etc */ + struct d10v_opcode * opcode; unsigned long insn; - int extype = 0; /* execution type; parallel, etc */ char * str2; - if (etype == 0) + if (etype == PACK_UNSPEC) { /* look for the special multiple instruction separators */ str2 = strstr (str, "||"); if (str2) - extype = 1; + extype = PACK_PARALLEL; else { str2 = strstr (str, "->"); if (str2) - extype = 2; + extype = PACK_LEFT_RIGHT; else { str2 = strstr (str, "<-"); if (str2) - extype = 3; + extype = PACK_RIGHT_LEFT; } } /* str2 points to the separator, if one */ @@ -1040,7 +1076,7 @@ md_assemble (str) *str2 = 0; /* if two instructions are present and we already have one saved - then first write it out */ + then first write out the save one */ d10v_cleanup (); /* assemble first instruction and save it */ @@ -1055,7 +1091,7 @@ md_assemble (str) insn = do_assemble (str, &opcode); if (insn == -1) { - if (extype) + if (extype != PACK_UNSPEC) { etype = extype; return; @@ -1063,16 +1099,16 @@ md_assemble (str) as_fatal (_("can't find opcode ")); } - if (etype) + if (etype != PACK_UNSPEC) { extype = etype; - etype = 0; + etype = PACK_UNSPEC; } /* if this is a long instruction, write it and any previous short instruction */ if (opcode->format & LONG_OPCODE) { - if (extype) + if (extype != PACK_UNSPEC) as_fatal (_("Unable to mix instructions as specified")); d10v_cleanup (); write_long (opcode, insn, fixups); @@ -1081,7 +1117,7 @@ md_assemble (str) } if (prev_opcode && prev_seg && ((prev_seg != now_seg) || (prev_subseg != now_subseg))) - d10v_cleanup(); + d10v_cleanup (); if (prev_opcode && (write_2_short (prev_opcode, prev_insn, opcode, insn, extype, fixups) == 0)) { @@ -1090,7 +1126,7 @@ md_assemble (str) } else { - if (extype) + if (extype != PACK_UNSPEC) as_fatal (_("Unable to mix instructions as specified")); /* save off last instruction so it may be packed on next pass */ prev_opcode = opcode; @@ -1570,14 +1606,16 @@ md_apply_fix3 (fixp, valuep, seg) /* d10v_cleanup() is called after the assembler has finished parsing the input file or after a label is defined. Because the D10V assembler sometimes saves short instructions to see if it can package them with the next instruction, there may - be a short instruction that still needs written. */ + be a short instruction that still needs written. + NOTE: accesses a global, etype. + NOTE: invoked by various macros such as md_cleanup: see. */ int d10v_cleanup () { segT seg; subsegT subseg; - if (prev_opcode && etype == 0) + if (prev_opcode && etype == PACK_UNSPEC) { seg = now_seg; subseg = now_subseg; -- 2.30.2