From 7a0f469b1cc5bcb780266abe0d61b5fa8a3d822c Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 9 Jun 1998 01:33:23 +0000 Subject: [PATCH] Foixes for PR16116 and ER15940 - improve parallel insn handling. --- gas/ChangeLog | 10 +++ gas/config/tc-d30v.c | 169 +++++++++++++++++++++++++++---------------- 2 files changed, 118 insertions(+), 61 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 739d6ea6bdb..29bc25aab83 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,13 @@ +Mon Jun 8 18:32:01 1998 Nick Clifton + + * config/tc-d30v.c (md_assemble): Fix handling of reverse + sequential word multiply instructions. + + (do_assemble): Add extra command line argument, to allow mul32 + attribute to be preserved across parallel insns. + (md_assemble): Insert NOPs between explicitly parallel insns which + contain an 32 bit multiply and a 16 multiply. + start-sanitize-sky Mon Jun 8 15:41:43 1998 Doug Evans diff --git a/gas/config/tc-d30v.c b/gas/config/tc-d30v.c index d22c2439d9b..dbf657b6ed1 100644 --- a/gas/config/tc-d30v.c +++ b/gas/config/tc-d30v.c @@ -111,7 +111,7 @@ static void write_1_short PARAMS ((struct d30v_insn *opcode, long long insn, Fix static int write_2_short PARAMS ((struct d30v_insn *opcode1, long long insn1, struct d30v_insn *opcode2, long long insn2, exec_type_enum exec_type, Fixups *fx)); static long long do_assemble PARAMS ((char *str, struct d30v_insn *opcode, - int shortp)); + int shortp, int is_parallel)); static int parallel_ok PARAMS ((struct d30v_insn *opcode1, unsigned long insn1, struct d30v_insn *opcode2, unsigned long insn2, exec_type_enum exec_type)); @@ -159,7 +159,7 @@ reg_name_search (name) int cmp; low = 0; - high = reg_name_cnt() - 1; + high = reg_name_cnt () - 1; do { @@ -245,7 +245,7 @@ void md_show_usage (stream) FILE *stream; { - fprintf(stream, _("\nD30V options:\n\ + fprintf (stream, _("\nD30V options:\n\ -O Make adjacent short instructions parallel if possible.\n\ -n Warn about all NOPs inserted by the assembler.\n\ -N Warn about NOPs inserted after word multiplies.\n")); @@ -352,7 +352,7 @@ void md_begin () { struct d30v_opcode *opcode; - d30v_hash = hash_new(); + d30v_hash = hash_new (); /* Insert opcode names into a hash table. */ for (opcode = (struct d30v_opcode *)d30v_opcode_table; opcode->name; opcode++) @@ -409,14 +409,14 @@ get_reloc (op, rel_flag) break; case 12: if (!(op->flags & OPERAND_SHIFT)) - as_warn(_("unexpected 12-bit reloc type")); + as_warn (_("unexpected 12-bit reloc type")); if (rel_flag == RELOC_PCREL) return BFD_RELOC_D30V_15_PCREL; else return BFD_RELOC_D30V_15; case 18: if (!(op->flags & OPERAND_SHIFT)) - as_warn(_("unexpected 18-bit reloc type")); + as_warn (_("unexpected 18-bit reloc type")); if (rel_flag == RELOC_PCREL) return BFD_RELOC_D30V_21_PCREL; else @@ -585,7 +585,7 @@ build_insn (opcode, opers) as_fatal (_("too many fixups")); fixups->fix[fixups->fc].reloc = - get_reloc((struct d30v_operand *)&d30v_operand_table[form->operands[i]], op->reloc_flag); + get_reloc ((struct d30v_operand *)&d30v_operand_table[form->operands[i]], op->reloc_flag); fixups->fix[fixups->fc].size = 4; fixups->fix[fixups->fc].exp = opers[i]; fixups->fix[fixups->fc].operand = form->operands[i]; @@ -598,7 +598,7 @@ build_insn (opcode, opers) /* truncate to the proper number of bits */ if ((opers[i].X_op == O_constant) && check_range (number, bits, flags)) - as_bad(_("operand out of range: %d"),number); + as_bad (_("operand out of range: %d"),number); if (bits < 31) number &= 0x7FFFFFFF >> (31 - bits); if (flags & OPERAND_SHIFT) @@ -626,7 +626,7 @@ write_long (opcode, insn, fx) Fixups *fx; { int i, where; - char *f = frag_more(8); + char *f = frag_more (8); insn |= FM11; d30v_number_to_chars (f, insn, 8); @@ -655,7 +655,7 @@ write_1_short (opcode, insn, fx) long long insn; Fixups *fx; { - char *f = frag_more(8); + char *f = frag_more (8); int i, where; if (warn_nops == NOP_ALL) @@ -700,7 +700,7 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) char *f; int i,j, where; - if(exec_type != EXEC_PARALLEL && + if (exec_type != EXEC_PARALLEL && ((opcode1->op->flags_used & (FLAG_JSR | FLAG_DELAY)) == FLAG_JSR)) { /* subroutines must be called from 32-bit boundaries */ @@ -782,11 +782,11 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) break; default: - as_fatal(_("unknown execution type passed to write_2_short()")); + as_fatal (_("unknown execution type passed to write_2_short()")); } /* printf("writing out %llx\n",insn); */ - f = frag_more(8); + f = frag_more (8); d30v_number_to_chars (f, insn, 8); /* If the previous instruction was a 32-bit multiply but it is put into a @@ -1030,7 +1030,7 @@ parallel_ok (op1, insn1, op2, insn2, exec_type) mod_reg[0][2] = mod_reg[1][2] = 0; } - for(j = 0; j < 3; j++) + for (j = 0; j < 3; j++) { /* If the second instruction depends on the first, we obviously cannot parallelize. Note, the mod flag implies use, so @@ -1078,7 +1078,7 @@ md_assemble (str) if ((prev_insn != -1) && prev_seg && ((prev_seg != now_seg) || (prev_subseg != now_subseg))) - d30v_cleanup(); + d30v_cleanup (); if (d30v_current_align < 3) d30v_align (3, NULL, d30v_last_label); @@ -1116,10 +1116,10 @@ md_assemble (str) /* if two instructions are present and we already have one saved then first write it out */ - d30v_cleanup(); + d30v_cleanup (); /* assemble first instruction and save it */ - prev_insn = do_assemble (str, &prev_opcode, 1); + prev_insn = do_assemble (str, &prev_opcode, 1, 0); if (prev_insn == -1) as_fatal (_("Cannot assemble instruction")); if (prev_opcode.form->form >= LONG) @@ -1132,7 +1132,8 @@ md_assemble (str) } insn = do_assemble (str, &opcode, - (extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN)); + (extype != EXEC_UNKNOWN || etype != EXEC_UNKNOWN), + extype == EXEC_PARALLEL); if (insn == -1) { if (extype != EXEC_UNKNOWN) @@ -1151,11 +1152,12 @@ md_assemble (str) /* Word multiply instructions must not be followed by either a load or a 16-bit multiply instruction in the next cycle. */ - if (prev_mul32_p && (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16))) + if ( (extype != EXEC_REVSEQ) + && prev_mul32_p + && (opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16))) { /* However, load and multiply should able to be combined in a parallel operation, so check for that first. */ - if (prev_insn != -1 && (opcode.op->flags_used & FLAG_MEM) && opcode.form->form < LONG @@ -1169,14 +1171,47 @@ md_assemble (str) prev_insn = -1; return; } - - /* Can't parallelize, flush current instruction and emit a word of NOPS */ else { - char *f; - d30v_cleanup(); + /* Can't parallelize, flush previous instruction and emit a word of NOPS, + unless the previous instruction is a NOP, in whcih case just flush it, + as this will generate a word of NOPs for us. */ - f = frag_more(8); + if (prev_insn != -1 && (strcmp (prev_opcode.op->name, "nop") == 0)) + { + d30v_cleanup (); + } + else + { + char * f; + + d30v_cleanup (); + + f = frag_more (8); + d30v_number_to_chars (f, NOP2, 8); + if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY) + { + if (opcode.op->flags_used & FLAG_MEM) + as_warn (_("word of NOPs added between word multiply and load")); + else + as_warn (_("word of NOPs added between word multiply and 16-bit multiply")); + } + } + extype = EXEC_UNKNOWN; + } + } + else if ( (extype == EXEC_REVSEQ) + && cur_mul32_p + && (prev_opcode.op->flags_used & (FLAG_MEM | FLAG_MUL16))) + { + /* Can't parallelize, flush current instruction and emit a word of NOPS */ + write_1_short (& opcode, (long) insn, fixups->next->next); + + if (strcmp (opcode.op->name, "nop") != 0) + { + char * f; + + f = frag_more (8); d30v_number_to_chars (f, NOP2, 8); if (warn_nops == NOP_ALL || warn_nops == NOP_MULTIPLY) { @@ -1185,34 +1220,40 @@ md_assemble (str) else as_warn (_("word of NOPs added between word multiply and 16-bit multiply")); } - extype = EXEC_UNKNOWN; } + + /* Make the previous instruction the current one. */ + extype = EXEC_UNKNOWN; + insn = prev_insn; + now_seg = prev_seg; + now_subseg = prev_subseg; + prev_insn = -1; + cur_mul32_p = prev_mul32_p; + prev_mul32_p = 0; } - /* if this is a long instruction, write it and any previous short instruction */ + /* If this is a long instruction, write it and any previous short instruction. */ if (opcode.form->form >= LONG) { - if (extype) - as_fatal(_("Unable to mix instructions as specified")); - d30v_cleanup(); + if (extype != EXEC_UNKNOWN) + as_fatal (_("Unable to mix instructions as specified")); + d30v_cleanup (); write_long (&opcode, insn, fixups); prev_insn = -1; - return; } - - if ((prev_insn != -1) && + else if ((prev_insn != -1) && (write_2_short (&prev_opcode, (long)prev_insn, &opcode, (long)insn, extype, fixups) == 0)) { - /* no instructions saved */ + /* No instructions saved. */ prev_insn = -1; } - else { - if (extype) - as_fatal(_("Unable to mix instructions as specified")); - /* save off last instruction so it may be packed on next pass */ - memcpy(&prev_opcode, &opcode, sizeof(prev_opcode)); + if (extype != EXEC_UNKNOWN) + as_fatal (_("Unable to mix instructions as specified")); + + /* Save off last instruction so it may be packed on next pass. */ + memcpy (&prev_opcode, &opcode, sizeof (prev_opcode)); prev_insn = insn; prev_seg = now_seg; prev_subseg = now_subseg; @@ -1225,10 +1266,11 @@ md_assemble (str) /* it returns -1 (an invalid opcode) on error */ static long long -do_assemble (str, opcode, shortp) +do_assemble (str, opcode, shortp, is_parallel) char *str; struct d30v_insn *opcode; int shortp; + int is_parallel; { unsigned char *op_start, *save; unsigned char *op_end; @@ -1249,7 +1291,7 @@ do_assemble (str, opcode, shortp) && !is_end_of_line[*op_end] && *op_end != ' '; op_end++) { - name[nlen] = tolower(op_start[nlen]); + name[nlen] = tolower (op_start[nlen]); nlen++; } @@ -1262,13 +1304,13 @@ do_assemble (str, opcode, shortp) if (*op_end == '/') { int i = 0; - while ( (i < ECC_MAX) && strncasecmp(d30v_ecc_names[i],op_end+1,2)) + while ( (i < ECC_MAX) && strncasecmp (d30v_ecc_names[i],op_end+1,2)) i++; if (i == ECC_MAX) { char tmp[4]; - strncpy(tmp,op_end+1,2); + strncpy (tmp,op_end+1,2); tmp[2] = 0; as_fatal (_("unknown condition code: %s"),tmp); return -1; @@ -1282,7 +1324,7 @@ do_assemble (str, opcode, shortp) /* CMP and CMPU change their name based on condition codes */ - if (!strncmp(name,"cmp",3)) + if (!strncmp (name,"cmp",3)) { int p,i; char **str = (char **)d30v_cc_names; @@ -1291,7 +1333,7 @@ do_assemble (str, opcode, shortp) else p = 3; - for(i=1; *str && strncmp(*str,&name[p],2); i++, str++) + for (i=1; *str && strncmp (*str,&name[p],2); i++, str++) ; /* cmpu only supports some condition codes */ @@ -1336,14 +1378,14 @@ do_assemble (str, opcode, shortp) /* find the first opcode with the proper name */ opcode->op = (struct d30v_opcode *)hash_find (d30v_hash, name); if (opcode->op == NULL) - as_fatal (_("unknown opcode: %s"),name); + as_fatal (_("unknown opcode: %s"),name); save = input_line_pointer; input_line_pointer = op_end; while (!(opcode->form = find_format (opcode->op, myops, fsize, cmp_hack))) { opcode->op++; - if (strcmp(opcode->op->name,name)) + if (strcmp (opcode->op->name,name)) as_fatal (_("operands for opcode `%s' do not match any valid format"), name); } input_line_pointer = save; @@ -1353,8 +1395,13 @@ do_assemble (str, opcode, shortp) /* Propigate multiply status */ if (insn != -1) { - prev_mul32_p = cur_mul32_p; - cur_mul32_p = (opcode->op->flags_used & FLAG_MUL32) != 0; + if (is_parallel && prev_mul32_p) + cur_mul32_p = 1; + else + { + prev_mul32_p = cur_mul32_p; + cur_mul32_p = (opcode->op->flags_used & FLAG_MUL32) != 0; + } } return (insn); @@ -1460,8 +1507,8 @@ find_format (opcode, myops, fsize, cmp_hack) match = 0; } else if (X_op == O_symbol - && S_IS_DEFINED(myops[j].X_add_symbol) - && S_GET_SEGMENT(myops[j].X_add_symbol) == now_seg + && S_IS_DEFINED (myops[j].X_add_symbol) + && S_GET_SEGMENT (myops[j].X_add_symbol) == now_seg && opcode->reloc_flag == RELOC_PCREL) { /* If the symbol is defined, see if the value will fit @@ -1474,8 +1521,8 @@ find_format (opcode, myops, fsize, cmp_hack) value = 0; for (f = frchain_now->frch_root; f; f = f->fr_next) value += f->fr_fix + f->fr_offset; - value = (S_GET_VALUE(myops[j].X_add_symbol) - value - - (obstack_next_free(&frchain_now->frch_obstack) + value = (S_GET_VALUE (myops[j].X_add_symbol) - value + - (obstack_next_free (&frchain_now->frch_obstack) - frag_now->fr_literal)); if (check_range (value, bits, flags)) match = 0; @@ -1709,15 +1756,15 @@ d30v_number_to_chars (buf, value, n) /* then write out any unwritten instructions */ void -d30v_start_line() +d30v_start_line () { char *c = input_line_pointer; - while(isspace(*c)) + while (isspace (*c)) c++; - if (*c == '.') - d30v_cleanup(); + if (*c == '.') + d30v_cleanup (); } static void @@ -1749,7 +1796,7 @@ d30v_frob_label (lab) symbolS *lab; { /* Emit any pending instructions. */ - d30v_cleanup(); + d30v_cleanup (); /* Update the label's address with the current output pointer. */ lab->sy_frag = frag_now; @@ -1797,7 +1844,7 @@ d30v_align (n, pfill, label) if (d30v_current_align >= n && !switched_seg_p) return; - d30v_cleanup(); + d30v_cleanup (); if (pfill == NULL) { @@ -1833,7 +1880,7 @@ d30v_align (n, pfill, label) old_frag = label->sy_frag; old_value = S_GET_VALUE (label); - new_value = (valueT) frag_now_fix(); + new_value = (valueT) frag_now_fix (); /* It is possible to have more than one label at a particular address, especially if debugging is enabled, so we must @@ -1859,7 +1906,7 @@ d30v_align (n, pfill, label) } } - record_alignment(now_seg, n); + record_alignment (now_seg, n); } /* Handle the .align pseudo-op. This aligns to a power of two. We -- 2.30.2