const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = "";
-const char *md_shortopts = "OnN";
+const char *md_shortopts = "OnNcC";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
#define NOP_ALL 2
static int warn_nops = 0;
static int Optimizing = 0;
+static int warn_register_name_conflicts = 1;
#define FORCE_SHORT 1
#define FORCE_LONG 2
static Fixups FixUps[2];
static Fixups *fixups;
-/* Whether current and previous instruction is a word multiply. */
+/* Whether current and previous instruction are word multiply insns. */
static int cur_mul32_p = 0;
static int prev_mul32_p = 0;
static int flag_explicitly_parallel = 0;
static int flag_xp_state = 0;
+/* Whether current and previous left sub-instruction disables
+ execution of right sub-instruction. */
+static int cur_left_kills_right_p = 0;
+static int prev_left_kills_right_p = 0;
+
/* The known current alignment of the current section. */
static int d30v_current_align;
static segT d30v_current_align_seg;
static symbolS *d30v_last_label;
/* Two nops */
-#define NOP_LEFT ((long long)NOP << 32)
-#define NOP_RIGHT ((long long)NOP)
+#define NOP_LEFT ((long long) NOP << 32)
+#define NOP_RIGHT ((long long) NOP)
#define NOP2 (FM00 | NOP_LEFT | NOP_RIGHT)
/* local functions */
expressionS ops[],int fsize, int cmp_hack));
static long long build_insn PARAMS ((struct d30v_insn *opcode, expressionS *opers));
static void write_long PARAMS ((struct d30v_insn *opcode, long long insn, Fixups *fx));
-static void write_1_short PARAMS ((struct d30v_insn *opcode, long long insn, Fixups *fx));
+static void write_1_short PARAMS ((struct d30v_insn *opcode, long long insn,
+ Fixups *fx, int use_sequential));
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,
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
- else
+ else
+ {
+ if (symbol_find (name) != NULL)
+ {
+ if (warn_register_name_conflicts)
+ as_warn (_("Register name %s conflicts with symbol of the same name"),
+ name);
+ }
+
return pre_defined_registers[middle].value;
+ }
}
while (low <= high);
+
return -1;
}
/* register_name() checks the string at input_line_pointer
- to see if it is a valid register name */
+ to see if it is a valid register name. */
static int
register_name (expressionP)
if (bits == 32)
return 0;
+ if (flags & OPERAND_SHIFT)
+ {
+ /* We know that all shifts are right by three bits.... */
+
+ if (flags & OPERAND_SIGNED)
+ num = (unsigned long) (((/*signed*/ long) num) >> 3);
+ else
+ num >>= 3;
+ }
+
if (flags & OPERAND_SIGNED)
{
max = (1 << (bits - 1))-1;
if ((num > max) || (num < min))
retval = 1;
}
+
return retval;
}
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"));
-}
+-N Warn about NOPs inserted after word multiplies.\n\
+-c Warn about symbols whoes names match register names.\n\
+-C Opposite of -C. -c is the default.\n"));
+}
int
md_parse_option (c, arg)
warn_nops = NOP_MULTIPLY;
break;
+ case 'c':
+ warn_register_name_conflicts = 1;
+ break;
+
+ case 'C':
+ warn_register_name_conflicts = 0;
+ break;
+
default:
return 0;
}
void
md_begin ()
{
- struct d30v_opcode *opcode;
+ struct d30v_opcode * opcode;
d30v_hash = hash_new ();
/* Insert opcode names into a hash table. */
}
-/* write out a short form instruction by itself */
+/* Write out a short form instruction by itself. */
static void
-write_1_short (opcode, insn, fx)
+write_1_short (opcode, insn, fx, use_sequential)
struct d30v_insn *opcode;
long long insn;
Fixups *fx;
+ int use_sequential;
{
char *f = frag_more (8);
int i, where;
if (warn_nops == NOP_ALL)
- as_warn (_("NOP inserted"));
+ as_warn (_("%s NOP inserted"), use_sequential ?
+ _("sequential") : _("parallel"));
- /* the other container needs to be NOP */
- /* according to 4.3.1: for FM=00, sub-instructions performed only
- by IU cannot be encoded in L-container. */
- if (opcode->op->unit == IU)
- insn |= FM00 | NOP_LEFT; /* right container */
+ /* The other container needs to be NOP. */
+ if (use_sequential)
+ {
+ /* Use a sequential NOP rather than a parallel one,
+ as the current instruction is a FLAG_MUL32 type one
+ and the next instruction is a load. */
+
+ /* According to 4.3.1: for FM=01, sub-instructions performed
+ only by IU cannot be encoded in L-container. */
+
+ if (opcode->op->unit == IU)
+ insn |= FM10 | NOP_LEFT; /* right then left */
+ else
+ insn = FM01 | (insn << 32) | NOP_RIGHT; /* left then right */
+ }
else
- insn = FM00 | (insn << 32) | NOP_RIGHT; /* left container */
+ {
+ /* According to 4.3.1: for FM=00, sub-instructions performed
+ only by IU cannot be encoded in L-container. */
+
+ if (opcode->op->unit == IU)
+ insn |= FM00 | NOP_LEFT; /* right container */
+ else
+ insn = FM00 | (insn << 32) | NOP_RIGHT; /* left container */
+ }
d30v_number_to_chars (f, insn, 8);
fx->fc = 0;
}
-/* write out a short form instruction if possible */
-/* return number of instructions not written out */
+/* Write out a short form instruction if possible.
+ Return number of instructions not written out. */
static int
write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
struct d30v_insn *opcode1, *opcode2;
char *f;
int i,j, where;
- if (exec_type != EXEC_PARALLEL &&
- ((opcode1->op->flags_used & (FLAG_JSR | FLAG_DELAY)) == FLAG_JSR))
+ if (exec_type == EXEC_SEQ
+ && (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR))
+ && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
+ && ((opcode1->ecc == ECC_AL) || ! Optimizing))
{
- /* subroutines must be called from 32-bit boundaries */
- /* so the return address will be correct */
- write_1_short (opcode1, insn1, fx->next);
- return (1);
+ /* Unconditional, non-delayed branches kill instructions in
+ the right bin. Conditional branches don't always but if
+ we are not optimizing, then we have been asked to produce
+ an error about such constructs. For the purposes of this
+ test, subroutine calls are considered to be branches. */
+ write_1_short (opcode1, insn1, fx->next, false);
+ return 1;
}
-
+
+ /* Note: we do not have to worry about subroutine calls occuring
+ in the right hand container. The return address is always
+ aligned to the next 64 bit boundary, be that 64 or 32 bit away. */
+
switch (exec_type)
{
- case EXEC_UNKNOWN: /* order not specified */
- if (Optimizing && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
+ case EXEC_UNKNOWN: /* Order not specified. */
+ if (Optimizing
+ && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)
+ && ! ( (opcode1->op->unit == EITHER_BUT_PREFER_MU
+ || opcode1->op->unit == MU)
+ &&
+ ( opcode2->op->unit == EITHER_BUT_PREFER_MU
+ || opcode2->op->unit == MU)))
{
/* parallel */
exec_type = EXEC_PARALLEL;
- if (opcode1->op->unit == IU)
- insn = FM00 | (insn2 << 32) | insn1;
- else if (opcode2->op->unit == MU)
+
+ if (opcode1->op->unit == IU
+ || opcode2->op->unit == MU
+ || opcode2->op->unit == EITHER_BUT_PREFER_MU)
insn = FM00 | (insn2 << 32) | insn1;
else
{
fx = fx->next;
}
}
- else if (opcode1->op->unit == IU)
+ else if (opcode1->op->flags_used & (FLAG_JMP | FLAG_JSR)
+ && ((opcode1->op->flags_used & FLAG_DELAY) == 0)
+ && ((opcode1->ecc == ECC_AL) || ! Optimizing))
+ {
+ /* We must emit (non-delayed) branch type instructions
+ on their own with nothing in the right container. */
+ write_1_short (opcode1, insn1, fx->next, false);
+ return 1;
+ }
+ else if (opcode1->op->unit == IU
+ || (opcode1->op->unit == EITHER
+ && opcode2->op->unit == EITHER_BUT_PREFER_MU))
{
/* reverse sequential */
insn = FM10 | (insn2 << 32) | insn1;
case EXEC_PARALLEL: /* parallel */
flag_explicitly_parallel = flag_xp_state;
if (! parallel_ok (opcode1, insn1, opcode2, insn2, exec_type))
- as_fatal (_("Instructions may not be executed in parallel"));
+ as_bad (_("Instructions may not be executed in parallel"));
else if (opcode1->op->unit == IU)
{
if (opcode2->op->unit == IU)
- as_fatal (_("Two IU instructions may not be executed in parallel"));
+ as_bad (_("Two IU instructions may not be executed in parallel"));
as_warn (_("Swapping instruction order"));
insn = FM00 | (insn2 << 32) | insn1;
}
else if (opcode2->op->unit == MU)
{
if (opcode1->op->unit == MU)
- as_fatal (_("Two MU instructions may not be executed in parallel"));
+ as_bad (_("Two MU instructions may not be executed in parallel"));
+ else if (opcode1->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode1->op->name);
as_warn (_("Swapping instruction order"));
insn = FM00 | (insn2 << 32) | insn1;
}
else
{
+ if (opcode2->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode2->op->name);
+
insn = FM00 | (insn1 << 32) | insn2;
fx = fx->next;
}
case EXEC_SEQ: /* sequential */
if (opcode1->op->unit == IU)
- as_fatal (_("IU instruction may not be in the left container"));
+ as_bad (_("IU instruction may not be in the left container"));
+ if (prev_left_kills_right_p)
+ as_bad (_("special left instruction `%s' kills instruction "
+ "`%s' in right container"),
+ opcode1->op->name, opcode2->op->name);
+ if (opcode2->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode2->op->name);
insn = FM01 | (insn1 << 32) | insn2;
fx = fx->next;
break;
case EXEC_REVSEQ: /* reverse sequential */
if (opcode2->op->unit == MU)
- as_fatal (_("MU instruction may not be in the right container"));
+ as_bad (_("MU instruction may not be in the right container"));
+ if (opcode2->op->unit == EITHER_BUT_PREFER_MU)
+ as_warn (_("Executing %s in IU may not work"), opcode2->op->name);
insn = FM10 | (insn1 << 32) | insn2;
fx = fx->next;
break;
as_fatal (_("unknown execution type passed to write_2_short()"));
}
- /* printf("writing out %llx\n",insn); */
+ /* printf ("writing out %llx\n",insn); */
f = frag_more (8);
d30v_number_to_chars (f, insn, 8);
fx->fix[i].reloc);
}
}
+
fx->fc = 0;
fx = fx->next;
}
- return (0);
+
+ return 0;
}
}
}
}
-
+
flags_set1 = op1->op->flags_set;
flags_set2 = op2->op->flags_set;
flags_used1 = op1->op->flags_used;
don't trust the human if both instructions modify the same
register but we do trust the human if they modify the same
flags. */
+ /* We have now been requested not to trust the human if the
+ instructions modify the same flag registers either. */
if (flag_explicitly_parallel)
{
- if ((j < 2) && (mod_reg[0][j] & mod_reg[1][j]) != 0)
+ if ((mod_reg[0][j] & mod_reg[1][j]) != 0)
return 0;
}
else
}
-
/* This is the main entry point for the machine-dependent assembler. str points to a
machine-dependent instruction. This function is supposed to emit the frags/bytes
it assembles to. For the D30V, it mostly handles the special VLIW parsing and packing
if ((prev_insn != -1) && prev_seg
&& ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
- d30v_cleanup ();
+ d30v_cleanup (false);
if (d30v_current_align < 3)
d30v_align (3, NULL, d30v_last_label);
/* if two instructions are present and we already have one saved
then first write it out */
- d30v_cleanup ();
+ d30v_cleanup (false);
- /* assemble first instruction and save it */
+ /* Assemble first instruction and save it. */
prev_insn = do_assemble (str, &prev_opcode, 1, 0);
if (prev_insn == -1)
- as_fatal (_("Cannot assemble instruction"));
+ as_bad (_("Cannot assemble instruction"));
if (prev_opcode.form->form >= LONG)
- as_fatal (_("First opcode is long. Unable to mix instructions as specified."));
+ as_bad (_("First opcode is long. Unable to mix instructions as specified."));
fixups = fixups->next;
str = str2 + 2;
prev_seg = now_seg;
etype = extype;
return;
}
- as_fatal (_("Cannot assemble instruction"));
+ as_bad (_("Cannot assemble instruction"));
}
if (etype != EXEC_UNKNOWN)
else
{
/* 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,
+ unless the previous instruction is a NOP, in which case just flush it,
as this will generate a word of NOPs for us. */
if (prev_insn != -1 && (strcmp (prev_opcode.op->name, "nop") == 0))
- {
- d30v_cleanup ();
- }
+ d30v_cleanup (false);
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 (prev_insn != -1)
+ d30v_cleanup (true);
+ else
{
- 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"));
+ 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;
}
}
&& 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)
- {
- 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"));
- }
- }
+ /* Can't parallelize, flush current instruction and add a sequential NOP. */
+ write_1_short (& opcode, (long) insn, fixups->next->next, true);
/* Make the previous instruction the current one. */
extype = EXEC_UNKNOWN;
prev_insn = -1;
cur_mul32_p = prev_mul32_p;
prev_mul32_p = 0;
+ memcpy (&opcode, &prev_opcode, sizeof (prev_opcode));
}
/* If this is a long instruction, write it and any previous short instruction. */
if (opcode.form->form >= LONG)
{
if (extype != EXEC_UNKNOWN)
- as_fatal (_("Unable to mix instructions as specified"));
- d30v_cleanup ();
- write_long (&opcode, insn, fixups);
+ as_bad (_("Instruction uses long version, so it cannot be mixed as specified"));
+ d30v_cleanup (false);
+ write_long (& opcode, insn, fixups);
prev_insn = -1;
}
- else if ((prev_insn != -1) &&
- (write_2_short (&prev_opcode, (long)prev_insn, &opcode, (long)insn, extype, fixups) == 0))
+ else if ((prev_insn != -1)
+ && (write_2_short
+ (& prev_opcode, (long) prev_insn, & opcode,
+ (long) insn, extype, fixups) == 0))
{
/* No instructions saved. */
prev_insn = -1;
else
{
if (extype != EXEC_UNKNOWN)
- as_fatal (_("Unable to mix instructions as specified"));
+ as_bad (_("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_seg = now_seg;
prev_subseg = now_subseg;
fixups = fixups->next;
+ prev_mul32_p = cur_mul32_p;
}
}
}
if (nlen == 0)
- return (-1);
+ return -1;
name[nlen] = 0;
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);
+ as_bad (_("unknown condition code: %s"),tmp);
return -1;
}
- /* printf("condition code=%d\n",i); */
+ /* printf ("condition code=%d\n",i); */
opcode->ecc = i;
op_end += 3;
}
/* 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;
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 */
if (i < 3 || i > 6)
{
name[p+2]=0;
- as_fatal (_("cmpu doesn't support condition code %s"),&name[p]);
+ as_bad (_("cmpu doesn't support condition code %s"),&name[p]);
}
}
if (!*str)
{
name[p+2]=0;
- as_fatal (_("unknown condition code: %s"),&name[p]);
+ as_bad (_("unknown condition code: %s"),&name[p]);
}
cmp_hack = i;
/* 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_bad (_("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))
- as_fatal (_("operands for opcode `%s' do not match any valid format"), name);
+ if (strcmp (opcode->op->name, name))
+ as_bad (_("operands for opcode `%s' do not match any valid format"), name);
}
input_line_pointer = save;
}
}
- return (insn);
+ /* Propagate left_kills_right status */
+ if (insn != -1)
+ {
+ prev_left_kills_right_p = cur_left_kills_right_p;
+
+ if (opcode->op->flags_set & FLAG_LKR)
+ {
+ cur_left_kills_right_p = 1;
+
+ if (strcmp (opcode->op->name, "mvtsys") == 0)
+ {
+ /* Left kills right for only mvtsys only for PSW/PSWH/PSWL/flags target. */
+ if ((myops[0].X_op == O_register) &&
+ ((myops[0].X_add_number == OPERAND_CONTROL) || /* psw */
+ (myops[0].X_add_number == OPERAND_CONTROL+MAX_CONTROL_REG+2) || /* pswh */
+ (myops[0].X_add_number == OPERAND_CONTROL+MAX_CONTROL_REG+1) || /* pswl */
+ (myops[0].X_add_number == OPERAND_FLAG+0) || /* f0 */
+ (myops[0].X_add_number == OPERAND_FLAG+1) || /* f1 */
+ (myops[0].X_add_number == OPERAND_FLAG+2) || /* f2 */
+ (myops[0].X_add_number == OPERAND_FLAG+3) || /* f3 */
+ (myops[0].X_add_number == OPERAND_FLAG+4) || /* f4 */
+ (myops[0].X_add_number == OPERAND_FLAG+5) || /* f5 */
+ (myops[0].X_add_number == OPERAND_FLAG+6) || /* f6 */
+ (myops[0].X_add_number == OPERAND_FLAG+7))) /* f7 */
+ {
+ cur_left_kills_right_p = 1;
+ }
+ else
+ {
+ /* Other mvtsys target registers don't kill right instruction. */
+ cur_left_kills_right_p = 0;
+ }
+ } /* mvtsys */
+ }
+ else
+ cur_left_kills_right_p = 0;
+ }
+
+
+ return insn;
}
{
if (X_op != O_register
|| ((flags & OPERAND_ACC) && !(num & OPERAND_ACC))
+ || (!(flags & OPERAND_ACC) && (num & OPERAND_ACC))
|| ((flags & OPERAND_FLAG) && !(num & OPERAND_FLAG))
+ || (!(flags & (OPERAND_FLAG | OPERAND_CONTROL)) && (num & OPERAND_FLAG))
|| ((flags & OPERAND_CONTROL)
&& !(num & (OPERAND_CONTROL | OPERAND_FLAG))))
{
{
/* A number can be a constant or symbol expression. */
+ /* If we have found a register name, but that name also
+ matches a symbol, then re-parse the name as an expression. */
+ if (X_op == O_register
+ && symbol_find ((char *) myops[j].X_op_symbol))
+ {
+ input_line_pointer = (char *) myops[j].X_op_symbol;
+ expression (& myops[j]);
+ }
+
/* Turn an expression into a symbol for later resolution. */
if (X_op != O_absent && X_op != O_constant
&& X_op != O_symbol && X_op != O_register
/* printf("through the loop: match=%d\n",match); */
/* We're only done if the operands matched so far AND there
are no more to check. */
- if (match && myops[j].X_op == 0)
- return fm;
+ if (match && myops[j].X_op == 0)
+ {
+ /* Final check - issue a warning if an odd numbered register
+ is used as the first register in an instruction that reads
+ or writes 2 registers. */
+
+ for (j = 0; fm->operands[j]; j++)
+ if (myops[j].X_op == O_register
+ && (myops[j].X_add_number & 1)
+ && (d30v_operand_table[fm->operands[j]].flags & OPERAND_2REG))
+ as_warn (\
+_("Odd numbered register used as target of multi-register instruction"));
+
+ return fm;
+ }
fm = (struct d30v_format *)&d30v_format_table[++k];
}
/* printf("trying another format: i=%d\n",i); */
int
md_apply_fix3 (fixp, valuep, seg)
- fixS *fixp;
- valueT *valuep;
+ fixS * fixp;
+ valueT * valuep;
segT seg;
{
- char *where;
+ char * where;
unsigned long insn, insn2;
long value;
-
+
if (fixp->fx_addsy == (symbolS *) NULL)
{
- value = *valuep;
+ value = * valuep;
fixp->fx_done = 1;
}
else if (fixp->fx_pcrel)
- {
- value = *valuep;
- }
+ value = * valuep;
else
{
value = fixp->fx_offset;
+
if (fixp->fx_subsy != (symbolS *) NULL)
{
if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
switch (fixp->fx_r_type)
{
+ case BFD_RELOC_8: /* Caused by a bad .byte directive. */
+ /* Drop trhough. */
+
+ case BFD_RELOC_16: /* Caused by a bad .short directive. */
+ /* Drop through. */
+
+ case BFD_RELOC_64: /* Caused by a bad .quad directive. */
+ {
+ char * size;
+
+ size = (fixp->fx_r_type == BFD_RELOC_8) ? _("byte")
+ : (fixp->fx_r_type == BFD_RELOC_16) ? _("short")
+ : _("quad");
+
+ if (fixp->fx_addsy == NULL)
+ as_bad (_("line %d: unable to place address into a %s"),
+ fixp->fx_line, size);
+ else
+ as_bad (_("line %d: unable to place address of symbol '%s' into a %s"),
+ fixp->fx_line,
+ S_GET_NAME (fixp->fx_addsy),
+ size);
+ break;
+ }
+
case BFD_RELOC_D30V_6:
check_size (value, 6, fixp->fx_file, fixp->fx_line);
insn |= value & 0x3F;
break;
default:
- as_fatal (_("line %d: unknown relocation type: 0x%x"),fixp->fx_line,fixp->fx_r_type);
+ as_bad (_("line %d: unknown relocation type: 0x%x"),
+ fixp->fx_line,fixp->fx_r_type);
}
+
return 0;
}
instructions to see if it can package them with the next instruction, there may
be a short instruction that still needs written. */
int
-d30v_cleanup ()
+d30v_cleanup (use_sequential)
+ int use_sequential;
{
segT seg;
subsegT subseg;
seg = now_seg;
subseg = now_subseg;
subseg_set (prev_seg, prev_subseg);
- write_1_short (&prev_opcode, (long)prev_insn, fixups->next);
+ write_1_short (&prev_opcode, (long)prev_insn, fixups->next, use_sequential);
subseg_set (seg, subseg);
prev_insn = -1;
+ if (use_sequential)
+ prev_mul32_p = false;
}
return 1;
}
c++;
if (*c == '.')
- d30v_cleanup ();
+ d30v_cleanup (false);
}
static void
symbolS *lab;
{
/* Emit any pending instructions. */
- d30v_cleanup ();
+ d30v_cleanup (false);
/* Update the label's address with the current output pointer. */
lab->sy_frag = frag_now;
temporarily when -g is in effect. */
int switched_seg_p = (d30v_current_align_seg != now_seg);
- if (d30v_current_align >= n && !switched_seg_p)
- return;
-
- d30v_cleanup ();
+ /* Do not assume that if 'd30v_current_align >= n' and
+ '! switched_seg_p' that it is safe to avoid performing
+ this alignement request. The alignment of the current frag
+ can be changed under our feet, for example by a .ascii
+ directive in the source code. cf testsuite/gas/d30v/reloc.s */
+
+ d30v_cleanup (false);
if (pfill == NULL)
{