/* tc-d10v.c -- Assembler code for the Mitsubishi D10V
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
- Free Software Foundation, Inc.
+ Copyright (C) 1996-2019 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
-#include <stdio.h>
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "opcode/d10v.h"
#include "elf/ppc.h"
+#include "dwarf2dbg.h"
-const char comment_chars[] = ";";
-const char line_comment_chars[] = "#";
+const char comment_chars[] = ";";
+const char line_comment_chars[] = "#";
const char line_separator_chars[] = "";
-const char *md_shortopts = "O";
-const char EXP_CHARS[] = "eE";
-const char FLT_CHARS[] = "dD";
+const char *md_shortopts = "O";
+const char EXP_CHARS[] = "eE";
+const char FLT_CHARS[] = "dD";
int Optimizing = 0;
#define AT_WORD_RIGHT_SHIFT 2
/* Fixups. */
-#define MAX_INSN_FIXUPS (5)
+#define MAX_INSN_FIXUPS 5
+
struct d10v_fixup
{
expressionS exp;
#define PACK_RIGHT_LEFT (3) /* "<-" */
static packing_type etype = PACK_UNSPEC; /* Used by d10v_cleanup. */
-/* True if instruction swapping warnings should be inhibited.
+/* TRUE if instruction swapping warnings should be inhibited.
--nowarnswap. */
-static boolean flag_warn_suppress_instructionswap;
+static bfd_boolean flag_warn_suppress_instructionswap;
-/* True if instruction packing should be performed when --gstabs is specified.
+/* TRUE if instruction packing should be performed when --gstabs is specified.
--gstabs-packing, --no-gstabs-packing. */
-static boolean flag_allow_gstabs_packing = 1;
+static bfd_boolean flag_allow_gstabs_packing = 1;
/* Local functions. */
-static int reg_name_search PARAMS ((char *name));
-static int register_name PARAMS ((expressionS *expressionP));
-static int check_range PARAMS ((unsigned long num, int bits, int flags));
-static int postfix PARAMS ((char *p));
-static bfd_reloc_code_real_type get_reloc PARAMS ((struct d10v_operand *op));
-static int get_operands PARAMS ((expressionS exp[]));
-static struct d10v_opcode *find_opcode PARAMS ((struct d10v_opcode *opcode, expressionS ops[]));
-static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers, unsigned long insn));
-static void write_long PARAMS ((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, 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,
- packing_type exec_type));
-
-static void check_resource_conflict PARAMS ((struct d10v_opcode *opcode1,
- unsigned long insn1,
- struct d10v_opcode *opcode2,
- unsigned long insn2));
-
-static symbolS * find_symbol_matching_register PARAMS ((expressionS *));
+
+enum options
+{
+ OPTION_NOWARNSWAP = OPTION_MD_BASE,
+ OPTION_GSTABSPACKING,
+ OPTION_NOGSTABSPACKING
+};
struct option md_longopts[] =
{
-#define OPTION_NOWARNSWAP (OPTION_MD_BASE)
{"nowarnswap", no_argument, NULL, OPTION_NOWARNSWAP},
-#define OPTION_GSTABSPACKING (OPTION_MD_BASE + 1)
{"gstabspacking", no_argument, NULL, OPTION_GSTABSPACKING},
{"gstabs-packing", no_argument, NULL, OPTION_GSTABSPACKING},
-#define OPTION_NOGSTABSPACKING (OPTION_MD_BASE + 2)
{"nogstabspacking", no_argument, NULL, OPTION_NOGSTABSPACKING},
{"no-gstabs-packing", no_argument, NULL, OPTION_NOGSTABSPACKING},
{NULL, no_argument, NULL, 0}
size_t md_longopts_size = sizeof (md_longopts);
-static void d10v_dot_word PARAMS ((int));
-
-/* The target specific pseudo-ops which we support. */
-const pseudo_typeS md_pseudo_table[] =
-{
- { "word", d10v_dot_word, 2 },
- { NULL, NULL, 0 }
-};
-
/* Opcode hash table. */
static struct hash_control *d10v_hash;
/* Do a binary search of the d10v_predefined_registers array to see if
- NAME is a valid regiter name. Return the register number from the
+ NAME is a valid register name. Return the register number from the
array on success, or -1 on failure. */
static int
-reg_name_search (name)
- char *name;
+reg_name_search (char *name)
{
int middle, low, high;
int cmp;
to see if it is a valid register name. */
static int
-register_name (expressionP)
- expressionS *expressionP;
+register_name (expressionS *expressionP)
{
int reg_number;
char c, *p = input_line_pointer;
}
static int
-check_range (num, bits, flags)
- unsigned long num;
- int bits;
- int flags;
+check_range (unsigned long num, int bits, int flags)
{
long min, max;
int retval = 0;
}
void
-md_show_usage (stream)
- FILE *stream;
+md_show_usage (FILE *stream)
{
fprintf (stream, _("D10V options:\n\
-O Optimize. Will do some operations in parallel.\n\
}
int
-md_parse_option (c, arg)
- int c;
- char *arg ATTRIBUTE_UNUSED;
+md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
{
switch (c)
{
}
symbolS *
-md_undefined_symbol (name)
- char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
return 0;
}
-/* Turn a string in input_line_pointer into a floating point constant
- of type TYPE, and store the appropriate bytes in *LITP. The number
- of LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
-
-char *
-md_atof (type, litP, sizeP)
- int type;
- char *litP;
- int *sizeP;
+const char *
+md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[4];
- char *t;
- int i;
-
- switch (type)
- {
- case 'f':
- prec = 2;
- break;
- case 'd':
- prec = 4;
- break;
- default:
- *sizeP = 0;
- return _("bad call to md_atof");
- }
-
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * 2;
-
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- return NULL;
+ return ieee_md_atof (type, litP, sizeP, TRUE);
}
void
-md_convert_frag (abfd, sec, fragP)
- bfd *abfd ATTRIBUTE_UNUSED;
- asection *sec ATTRIBUTE_UNUSED;
- fragS *fragP ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec ATTRIBUTE_UNUSED,
+ fragS *fragP ATTRIBUTE_UNUSED)
{
abort ();
}
valueT
-md_section_align (seg, addr)
- asection *seg;
- valueT addr;
+md_section_align (asection *seg, valueT addr)
{
- int align = bfd_get_section_alignment (stdoutput, seg);
- return ((addr + (1 << align) - 1) & (-1 << align));
+ int align = bfd_section_alignment (seg);
+ return ((addr + (1 << align) - 1) & -(1 << align));
}
void
-md_begin ()
+md_begin (void)
{
- char *prev_name = "";
+ const char *prev_name = "";
struct d10v_opcode *opcode;
d10v_hash = hash_new ();
from an expression. */
static int
-postfix (p)
- char *p;
+postfix (char *p)
{
while (*p != '-' && *p != '+')
{
if (*p == '-')
{
*p = ' ';
- return (-1);
+ return -1;
}
if (*p == '+')
{
*p = ' ';
- return (1);
+ return 1;
}
- return (0);
+ return 0;
}
static bfd_reloc_code_real_type
-get_reloc (op)
- struct d10v_operand *op;
+get_reloc (struct d10v_operand *op)
{
int bits = op->bits;
if (bits <= 4)
- return (0);
+ return 0;
if (op->flags & OPERAND_ADDR)
{
if (bits == 8)
- return (BFD_RELOC_D10V_10_PCREL_R);
+ return BFD_RELOC_D10V_10_PCREL_R;
else
- return (BFD_RELOC_D10V_18_PCREL);
+ return BFD_RELOC_D10V_18_PCREL;
}
- return (BFD_RELOC_16);
+ return BFD_RELOC_16;
}
/* Parse a string of operands. Return an array of expressions. */
static int
-get_operands (exp)
- expressionS exp[];
+get_operands (expressionS exp[])
{
char *p = input_line_pointer;
int numops = 0;
}
exp[numops].X_op = 0;
- return (numops);
+ return numops;
}
static unsigned long
-d10v_insert_operand (insn, op_type, value, left, fix)
- unsigned long insn;
- int op_type;
- offsetT value;
- int left;
- fixS *fix;
+d10v_insert_operand (unsigned long insn,
+ int op_type,
+ offsetT value,
+ int left,
+ fixS *fix)
{
int shift, bits;
array of operand expressions. Return the instruction. */
static unsigned long
-build_insn (opcode, opers, insn)
- struct d10v_opcode *opcode;
- expressionS *opers;
- unsigned long insn;
+build_insn (struct d10v_opcode *opcode,
+ expressionS *opers,
+ unsigned long insn)
{
int i, bits, shift, flags, format;
unsigned long number;
if (AT_WORD_P (&opers[i]))
{
- /* Reconize XXX>>1+N aka XXX@word+N as special (AT_WORD). */
+ /* Recognize XXX>>1+N aka XXX@word+N as special (AT_WORD). */
fixups->fix[fixups->fc].reloc = BFD_RELOC_D10V_18;
opers[i].X_op = O_symbol;
opers[i].X_op_symbol = NULL; /* Should free it. */
fixups->fix[fixups->fc].reloc =
get_reloc ((struct d10v_operand *) &d10v_operands[opcode->operands[i]]);
- /* Check that a immediate was passed to ops that expect one. */
- if ((flags & OPERAND_NUM)
+ /* Check that an immediate was passed to ops that expect one. */
+ if ((flags & OPERAND_NUM)
&& (fixups->fix[fixups->fc].reloc == 0))
as_bad (_("operand is not an immediate"));
}
fixups->fix[fixups->fc].exp = opers[i];
fixups->fix[fixups->fc].operand = opcode->operands[i];
fixups->fix[fixups->fc].pcrel =
- (flags & OPERAND_ADDR) ? true : false;
+ (flags & OPERAND_ADDR) ? TRUE : FALSE;
(fixups->fc)++;
}
-
+
/* 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: %lu"), number);
insn = insn | (number << shift);
}
- /* kludge: for DIVS, we need to put the operands in twice on the second
- pass, format is changed to LONG_R to force the second set of operands
+ /* kludge: for DIVS, we need to put the operands in twice on the second
+ pass, format is changed to LONG_R to force the second set of operands
to not be shifted over 15. */
if ((opcode->opcode == OPCODE_DIVS) && (format == LONG_L))
insn = build_insn (opcode, opers, insn);
/* Write out a long form instruction. */
static void
-write_long (insn, fx)
- unsigned long insn;
- Fixups *fx;
+write_long (unsigned long insn, Fixups *fx)
{
int i, where;
char *f = frag_more (4);
+ dwarf2_emit_insn (4);
insn |= FM11;
number_to_chars_bigendian (f, insn, 4);
/* Write out a short form instruction by itself. */
static void
-write_1_short (opcode, insn, fx)
- struct d10v_opcode *opcode;
- unsigned long insn;
- Fixups *fx;
+write_1_short (struct d10v_opcode *opcode,
+ unsigned long insn,
+ Fixups *fx)
{
char *f = frag_more (4);
int i, where;
+ dwarf2_emit_insn (4);
if (opcode->exec_type & PARONLY)
as_fatal (_("Instruction must be executed in parallel with another instruction."));
- /* The other container needs to be NOP.
- According to 4.3.1: for FM=00, sub-instructions performed only by IU
+ /* 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->unit == IU)
insn |= FM00 | (NOP << 15); /* Right container. */
fx->fc = 0;
}
-/* 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. */
+/* Determine if there are any resource conflicts among two manually
+ parallelized instructions. Some of this was lifted from parallel_ok. */
-static int
-write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
- struct d10v_opcode *opcode1, *opcode2;
- unsigned long insn1, insn2;
- packing_type exec_type;
- Fixups *fx;
+static void
+check_resource_conflict (struct d10v_opcode *op1,
+ unsigned long insn1,
+ struct d10v_opcode *op2,
+ unsigned long insn2)
{
- unsigned long insn;
- char *f;
- int i, j, where;
-
- 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."));
+ int i, j, flags, mask, shift, regno;
+ unsigned long ins, mod[2];
+ struct d10v_opcode *op;
- switch (exec_type)
+ if ((op1->exec_type & SEQ)
+ || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY)))
{
- 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)
- insn = FM00 | (insn2 << 15) | insn1;
- else if (opcode2->unit == MU)
- insn = FM00 | (insn2 << 15) | insn1;
- else
- insn = FM00 | (insn1 << 15) | insn2;
- }
- else if (opcode1->unit == IU)
- /* Reverse sequential with IU opcode1 on right and done first. */
- insn = FM10 | (insn2 << 15) | insn1;
- else
- /* Sequential with non-IU opcode1 on left and done first. */
- insn = FM01 | (insn1 << 15) | insn2;
- break;
-
- 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)
- as_fatal (_("Two IU instructions may not be executed in parallel"));
- if (!flag_warn_suppress_instructionswap)
- as_warn (_("Swapping instruction order"));
- insn = FM00 | (insn2 << 15) | insn1;
- }
- else if (opcode2->unit == MU)
- {
- if (opcode1->unit == MU)
- as_fatal (_("Two MU instructions may not be executed in parallel"));
- if (!flag_warn_suppress_instructionswap)
- as_warn (_("Swapping instruction order"));
- insn = FM00 | (insn2 << 15) | insn1;
- }
- else
- insn = FM00 | (insn1 << 15) | insn2;
- check_resource_conflict (opcode1, insn1, opcode2, insn2);
- break;
-
- 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;
- }
- 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."));
- break;
-
- case PACK_RIGHT_LEFT:
- if (opcode2->unit != MU)
- insn = FM10 | (insn1 << 15) | insn2;
- else if (opcode1->unit == IU || opcode1->unit == EITHER)
- {
- if (!flag_warn_suppress_instructionswap)
- as_warn (_("Swapping instruction order"));
- insn = FM01 | (insn2 << 15) | insn1;
- }
- 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."));
- break;
-
- default:
- as_fatal (_("unknown execution type passed to write_2_short()"));
+ as_warn (_("packing conflict: %s must dispatch sequentially"),
+ op1->name);
+ return;
}
- f = frag_more (4);
- number_to_chars_bigendian (f, insn, 4);
-
- /* Process fixup chains. fx refers to insn2 when j == 0, and to
- insn1 when j == 1. Yes, it's reversed. */
-
- for (j = 0; j < 2; j++)
+ if ((op2->exec_type & SEQ)
+ || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY)))
{
- for (i = 0; i < fx->fc; i++)
- {
- if (fx->fix[i].reloc)
- {
- where = f - frag_now->fr_literal;
- if (fx->fix[i].size == 2)
- where += 2;
-
- if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R
- /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to
- the instruction in the L container has to be
- adjusted to BDF_RELOC_D10V_10_PCREL_L. When
- j==0, we're processing insn2's operands, so we
- want to mark the operand if insn2 is *not* in the
- R container. When j==1, we're processing insn1's
- operands, so we want to mark the operand if insn2
- *is* in the R container. Note that, if two
- instructions are identical, we're never going to
- swap them, so the test is safe. */
- && j == ((insn & 0x7fff) == insn2))
- fx->fix[i].operand |= 1024;
-
- if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
- fx->fix[i].operand |= 4096;
-
- fix_new_exp (frag_now,
- where,
- fx->fix[i].size,
- &(fx->fix[i].exp),
- fx->fix[i].pcrel,
- fx->fix[i].operand|2048);
- }
- }
- fx->fc = 0;
- fx = fx->next;
+ as_warn (_("packing conflict: %s must dispatch sequentially"),
+ op2->name);
+ return;
}
- return (0);
-}
-
-/* Check 2 instructions and determine if they can be safely
- executed in parallel. Return 1 if they can be. */
-
-static int
-parallel_ok (op1, insn1, op2, insn2, exec_type)
- struct d10v_opcode *op1, *op2;
- unsigned long insn1, insn2;
- packing_type exec_type;
-{
- int i, j, flags, mask, shift, regno;
- unsigned long ins, mod[2], used[2];
- struct d10v_opcode *op;
-
- if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0
- || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0
- || (op1->unit == BOTH) || (op2->unit == BOTH)
- || (op1->unit == IU && op2->unit == IU)
- || (op1->unit == MU && op2->unit == MU))
- return 0;
- /* If this is auto parallelization, and the first instruction is a
- branch or should not be packed, then don't parallelize. */
- if (exec_type == PACK_UNSPEC
- && (op1->exec_type & (ALONE | BRANCH)))
- return 0;
+ /* See if both instructions write to the same resource.
- /* The idea here is to create two sets of bitmasks (mod and used)
- which indicate which registers are modified or used by each
- instruction. The operation can only be done in parallel if
- instruction 1 and instruction 2 modify different registers, and
- the first instruction does not modify registers that the second
- is using (The second instruction can modify registers that the
- first is using as they are only written back after the first
- instruction has completed). Accesses to control registers, PSW,
- and memory are treated as accesses to a single register. So if
- both instructions write memory or if the first instruction writes
- memory and the second reads, then they cannot be done in
- parallel. Likewise, if the first instruction mucks with the psw
- and the second reads the PSW (which includes C, F0, and F1), then
- they cannot operate safely in parallel. */
+ The idea here is to create two sets of bitmasks (mod and used) which
+ indicate which registers are modified or used by each instruction.
+ The operation can only be done in parallel if neither instruction
+ modifies the same register. Accesses to control registers and memory
+ are treated as accesses to a single register. So if both instructions
+ write memory or if the first instruction writes memory and the second
+ reads, then they cannot be done in parallel. We treat reads to the PSW
+ (which includes C, F0, and F1) in isolation. So simultaneously writing
+ C and F0 in two different sub-instructions is permitted. */
- /* The bitmasks (mod and used) look like this (bit 31 = MSB).
- r0-r15 0-15
+ /* The bitmasks (mod and used) look like this (bit 31 = MSB).
+ r0-r15 0-15
a0-a1 16-17
cr (not psw) 18
- psw 19
- mem 20 */
+ psw(other) 19
+ mem 20
+ psw(C flag) 21
+ psw(F0 flag) 22 */
for (j = 0; j < 2; j++)
{
op = op2;
ins = insn2;
}
- mod[j] = used[j] = 0;
+ mod[j] = 0;
if (op->exec_type & BRANCH_LINK)
mod[j] |= 1 << 13;
regno = (ins >> shift) & mask;
if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
regno += 16;
- else if (flags & OPERAND_CONTROL) /* mvtc or mvfc. */
+ else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
{
if (regno == 0)
regno = 19;
else
regno = 18;
}
- else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))
- regno = 19;
+ else if (flags & OPERAND_FFLAG)
+ regno = 22;
+ else if (flags & OPERAND_CFLAG)
+ regno = 21;
- if (flags & OPERAND_DEST)
+ if (flags & OPERAND_DEST
+ /* Auto inc/dec also modifies the register. */
+ || (op->operands[i + 1] != 0
+ && (d10v_operands[op->operands[i + 1]].flags
+ & (OPERAND_PLUS | OPERAND_MINUS)) != 0))
{
mod[j] |= 1 << regno;
if (flags & OPERAND_EVEN)
mod[j] |= 1 << (regno + 1);
}
- else
- {
- used[j] |= 1 << regno;
- if (flags & OPERAND_EVEN)
- used[j] |= 1 << (regno + 1);
-
- /* Auto inc/dec also modifies the register. */
- if (op->operands[i + 1] != 0
- && (d10v_operands[op->operands[i + 1]].flags
- & (OPERAND_PLUS | OPERAND_MINUS)) != 0)
- mod[j] |= 1 << regno;
- }
}
else if (flags & OPERAND_ATMINUS)
{
/* SP implicitly used/modified. */
mod[j] |= 1 << 15;
- used[j] |= 1 << 15;
}
}
- if (op->exec_type & RMEM)
- used[j] |= 1 << 20;
- else if (op->exec_type & WMEM)
+
+ if (op->exec_type & WMEM)
mod[j] |= 1 << 20;
- else if (op->exec_type & RF0)
- used[j] |= 1 << 19;
else if (op->exec_type & WF0)
- mod[j] |= 1 << 19;
+ mod[j] |= 1 << 22;
else if (op->exec_type & WCAR)
- mod[j] |= 1 << 19;
+ mod[j] |= 1 << 21;
+ }
+
+ if ((mod[0] & mod[1]) == 0)
+ return;
+ else
+ {
+ unsigned long x;
+ x = mod[0] & mod[1];
+
+ for (j = 0; j <= 15; j++)
+ if (x & (1 << j))
+ as_warn (_("resource conflict (R%d)"), j);
+ for (j = 16; j <= 17; j++)
+ if (x & (1 << j))
+ as_warn (_("resource conflict (A%d)"), j - 16);
+ if (x & (1 << 19))
+ as_warn (_("resource conflict (PSW)"));
+ if (x & (1 << 21))
+ as_warn (_("resource conflict (C flag)"));
+ if (x & (1 << 22))
+ as_warn (_("resource conflict (F flag)"));
}
- if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)
- return 1;
- return 0;
}
-/* Determine if there are any resource conflicts among two manually
- parallelized instructions. Some of this was lifted from parallel_ok. */
+/* Check 2 instructions and determine if they can be safely
+ executed in parallel. Return 1 if they can be. */
-static void
-check_resource_conflict (op1, insn1, op2, insn2)
- struct d10v_opcode *op1, *op2;
- unsigned long insn1, insn2;
+static int
+parallel_ok (struct d10v_opcode *op1,
+ unsigned long insn1,
+ struct d10v_opcode *op2,
+ unsigned long insn2,
+ packing_type exec_type)
{
int i, j, flags, mask, shift, regno;
- unsigned long ins, mod[2];
+ unsigned long ins, mod[2], used[2];
struct d10v_opcode *op;
- if ((op1->exec_type & SEQ)
- || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY)))
- {
- as_warn (_("packing conflict: %s must dispatch sequentially"),
- op1->name);
- return;
- }
-
- if ((op2->exec_type & SEQ)
- || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY)))
- {
- as_warn (_("packing conflict: %s must dispatch sequentially"),
- op2->name);
- return;
- }
+ if ((op1->exec_type & SEQ) != 0 || (op2->exec_type & SEQ) != 0
+ || (op1->exec_type & PAR) == 0 || (op2->exec_type & PAR) == 0
+ || (op1->unit == BOTH) || (op2->unit == BOTH)
+ || (op1->unit == IU && op2->unit == IU)
+ || (op1->unit == MU && op2->unit == MU))
+ return 0;
- /* See if both instructions write to the same resource.
+ /* If this is auto parallelization, and the first instruction is a
+ branch or should not be packed, then don't parallelize. */
+ if (exec_type == PACK_UNSPEC
+ && (op1->exec_type & (ALONE | BRANCH)))
+ return 0;
- The idea here is to create two sets of bitmasks (mod and used) which
- indicate which registers are modified or used by each instruction.
- The operation can only be done in parallel if neither instruction
- modifies the same register. Accesses to control registers and memory
- are treated as accesses to a single register. So if both instructions
- write memory or if the first instruction writes memory and the second
- reads, then they cannot be done in parallel. We treat reads to the PSW
- (which includes C, F0, and F1) in isolation. So simultaneously writing
- C and F0 in two different sub-instructions is permitted. */
+ /* The idea here is to create two sets of bitmasks (mod and used)
+ which indicate which registers are modified or used by each
+ instruction. The operation can only be done in parallel if
+ instruction 1 and instruction 2 modify different registers, and
+ the first instruction does not modify registers that the second
+ is using (The second instruction can modify registers that the
+ first is using as they are only written back after the first
+ instruction has completed). Accesses to control registers, PSW,
+ and memory are treated as accesses to a single register. So if
+ both instructions write memory or if the first instruction writes
+ memory and the second reads, then they cannot be done in
+ parallel. Likewise, if the first instruction mucks with the psw
+ and the second reads the PSW (which includes C, F0, and F1), then
+ they cannot operate safely in parallel. */
/* The bitmasks (mod and used) look like this (bit 31 = MSB).
r0-r15 0-15
a0-a1 16-17
cr (not psw) 18
- psw(other) 19
- mem 20
- psw(C flag) 21
- psw(F0 flag) 22 */
+ psw 19
+ mem 20 */
for (j = 0; j < 2; j++)
{
op = op2;
ins = insn2;
}
- mod[j] = 0;
+ mod[j] = used[j] = 0;
if (op->exec_type & BRANCH_LINK)
mod[j] |= 1 << 13;
regno = (ins >> shift) & mask;
if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
regno += 16;
- else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
- {
+ else if (flags & OPERAND_CONTROL) /* mvtc or mvfc. */
+ {
if (regno == 0)
regno = 19;
else
- regno = 18;
+ regno = 18;
}
- else if (flags & OPERAND_FFLAG)
- regno = 22;
- else if (flags & OPERAND_CFLAG)
- regno = 21;
-
- if (flags & OPERAND_DEST
- /* Auto inc/dec also modifies the register. */
- || (op->operands[i + 1] != 0
- && (d10v_operands[op->operands[i + 1]].flags
- & (OPERAND_PLUS | OPERAND_MINUS)) != 0))
+ else if (flags & (OPERAND_FFLAG | OPERAND_CFLAG))
+ regno = 19;
+
+ if (flags & OPERAND_DEST)
{
mod[j] |= 1 << regno;
if (flags & OPERAND_EVEN)
mod[j] |= 1 << (regno + 1);
}
+ else
+ {
+ used[j] |= 1 << regno;
+ if (flags & OPERAND_EVEN)
+ used[j] |= 1 << (regno + 1);
+
+ /* Auto inc/dec also modifies the register. */
+ if (op->operands[i + 1] != 0
+ && (d10v_operands[op->operands[i + 1]].flags
+ & (OPERAND_PLUS | OPERAND_MINUS)) != 0)
+ mod[j] |= 1 << regno;
+ }
}
else if (flags & OPERAND_ATMINUS)
{
/* SP implicitly used/modified. */
mod[j] |= 1 << 15;
+ used[j] |= 1 << 15;
}
}
-
- if (op->exec_type & WMEM)
+ if (op->exec_type & RMEM)
+ used[j] |= 1 << 20;
+ else if (op->exec_type & WMEM)
mod[j] |= 1 << 20;
+ else if (op->exec_type & RF0)
+ used[j] |= 1 << 19;
else if (op->exec_type & WF0)
- mod[j] |= 1 << 22;
+ mod[j] |= 1 << 19;
else if (op->exec_type & WCAR)
- mod[j] |= 1 << 21;
- }
-
- if ((mod[0] & mod[1]) == 0)
- return;
- else
- {
- unsigned long x;
- x = mod[0] & mod[1];
-
- for (j = 0; j <= 15; j++)
- if (x & (1 << j))
- as_warn (_("resource conflict (R%d)"), j);
- for (j = 16; j <= 17; j++)
- if (x & (1 << j))
- as_warn (_("resource conflict (A%d)"), j - 16);
- if (x & (1 << 19))
- as_warn (_("resource conflict (PSW)"));
- if (x & (1 << 21))
- as_warn (_("resource conflict (C flag)"));
- if (x & (1 << 22))
- as_warn (_("resource conflict (F flag)"));
+ mod[j] |= 1 << 19;
}
+ if ((mod[0] & mod[1]) == 0 && (mod[0] & used[1]) == 0)
+ return 1;
+ return 0;
}
-/* 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 D10V, it
- mostly handles the special VLIW parsing and packing and leaves the
- difficult stuff to do_assemble(). */
-
-static unsigned long prev_insn;
-static struct d10v_opcode *prev_opcode = 0;
-static subsegT prev_subseg;
-static segT prev_seg = 0;;
+/* 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. */
-void
-md_assemble (str)
- char *str;
+static int
+write_2_short (struct d10v_opcode *opcode1,
+ unsigned long insn1,
+ struct d10v_opcode *opcode2,
+ unsigned long insn2,
+ packing_type exec_type,
+ Fixups *fx)
{
- /* etype is saved extype. For multi-line instructions. */
+ unsigned long insn;
+ char *f;
+ int i, j, where;
- packing_type extype = PACK_UNSPEC; /* Parallel, etc. */
+ if ((exec_type != PACK_PARALLEL)
+ && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY)))
+ as_fatal (_("Instruction must be executed in parallel"));
- struct d10v_opcode *opcode;
- unsigned long insn;
- char *str2;
+ if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE))
+ as_fatal (_("Long instructions may not be combined."));
- if (etype == PACK_UNSPEC)
+ switch (exec_type)
{
- /* Look for the special multiple instruction separators. */
- str2 = strstr (str, "||");
- if (str2)
- extype = PACK_PARALLEL;
- else
+ case PACK_UNSPEC: /* Order not specified. */
+ if (opcode1->exec_type & ALONE)
{
- str2 = strstr (str, "->");
- if (str2)
- extype = PACK_LEFT_RIGHT;
+ /* 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)
+ insn = FM00 | (insn2 << 15) | insn1;
+ else if (opcode2->unit == MU)
+ insn = FM00 | (insn2 << 15) | insn1;
else
- {
- str2 = strstr (str, "<-");
- if (str2)
- extype = PACK_RIGHT_LEFT;
- }
+ insn = FM00 | (insn1 << 15) | insn2;
}
+ else if (opcode1->unit == IU)
+ /* Reverse sequential with IU opcode1 on right and done first. */
+ insn = FM10 | (insn2 << 15) | insn1;
+ else
+ /* Sequential with non-IU opcode1 on left and done first. */
+ insn = FM01 | (insn1 << 15) | insn2;
+ break;
- /* str2 points to the separator, if there is one. */
- if (str2)
+ 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)
{
- *str2 = 0;
-
- /* If two instructions are present and we already have one saved,
- then first write out the saved one. */
- d10v_cleanup ();
-
- /* Assemble first instruction and save it. */
- prev_insn = do_assemble (str, &prev_opcode);
- prev_seg = now_seg;
- prev_subseg = now_subseg;
- if (prev_insn == (unsigned long) -1)
- as_fatal (_("can't find opcode "));
- fixups = fixups->next;
- str = str2 + 2;
+ if (opcode2->unit == IU)
+ as_fatal (_("Two IU instructions may not be executed in parallel"));
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
+ insn = FM00 | (insn2 << 15) | insn1;
}
- }
-
- insn = do_assemble (str, &opcode);
- if (insn == (unsigned long) -1)
- {
- if (extype != PACK_UNSPEC)
+ else if (opcode2->unit == MU)
{
- etype = extype;
- return;
+ if (opcode1->unit == MU)
+ as_fatal (_("Two MU instructions may not be executed in parallel"));
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
+ insn = FM00 | (insn2 << 15) | insn1;
}
- as_fatal (_("can't find opcode "));
- }
-
- if (etype != PACK_UNSPEC)
- {
- extype = etype;
- etype = PACK_UNSPEC;
- }
-
- /* If this is a long instruction, write it and any previous short
- instruction. */
- if (opcode->format & LONG_OPCODE)
- {
- if (extype != PACK_UNSPEC)
- as_fatal (_("Unable to mix instructions as specified"));
- d10v_cleanup ();
- write_long (insn, fixups);
- prev_opcode = NULL;
- return;
- }
+ else
+ insn = FM00 | (insn1 << 15) | insn2;
+ check_resource_conflict (opcode1, insn1, opcode2, insn2);
+ break;
- if (prev_opcode
- && prev_seg
- && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
- d10v_cleanup ();
+ 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;
+ }
+ 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."));
+ break;
- if (prev_opcode
- && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype,
- fixups)))
- {
- /* No instructions saved. */
- prev_opcode = NULL;
- }
- else
- {
- if (extype != PACK_UNSPEC)
- as_fatal (_("Unable to mix instructions as specified"));
- /* Save last instruction so it may be packed on next pass. */
- prev_opcode = opcode;
- prev_insn = insn;
- prev_seg = now_seg;
- prev_subseg = now_subseg;
- fixups = fixups->next;
- }
-}
+ case PACK_RIGHT_LEFT:
+ if (opcode2->unit != MU)
+ insn = FM10 | (insn1 << 15) | insn2;
+ else if (opcode1->unit == IU || opcode1->unit == EITHER)
+ {
+ if (!flag_warn_suppress_instructionswap)
+ as_warn (_("Swapping instruction order"));
+ insn = FM01 | (insn2 << 15) | insn1;
+ }
+ 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."));
+ break;
-/* Assemble a single instruction.
- Return an opcode, or -1 (an invalid opcode) on error. */
+ default:
+ as_fatal (_("unknown execution type passed to write_2_short()"));
+ }
-static unsigned long
-do_assemble (str, opcode)
- char *str;
- struct d10v_opcode **opcode;
-{
- unsigned char *op_start, *save;
- unsigned char *op_end;
- char name[20];
- int nlen = 0;
- expressionS myops[6];
- unsigned long insn;
+ f = frag_more (4);
+ dwarf2_emit_insn (4);
+ number_to_chars_bigendian (f, insn, 4);
- /* Drop leading whitespace. */
- while (*str == ' ')
- str++;
+ /* Process fixup chains. fx refers to insn2 when j == 0, and to
+ insn1 when j == 1. Yes, it's reversed. */
- /* Find the opcode end. */
- for (op_start = op_end = (unsigned char *) (str);
- *op_end
- && nlen < 20
- && !is_end_of_line[*op_end] && *op_end != ' ';
- op_end++)
+ for (j = 0; j < 2; j++)
{
- name[nlen] = TOLOWER (op_start[nlen]);
- nlen++;
- }
- name[nlen] = 0;
-
- if (nlen == 0)
- return -1;
+ for (i = 0; i < fx->fc; i++)
+ {
+ if (fx->fix[i].reloc)
+ {
+ where = f - frag_now->fr_literal;
+ if (fx->fix[i].size == 2)
+ where += 2;
- /* Find the first opcode with the proper name. */
- *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name);
- if (*opcode == NULL)
- as_fatal (_("unknown opcode: %s"), name);
+ if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R
+ /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to
+ the instruction in the L container has to be
+ adjusted to BDF_RELOC_D10V_10_PCREL_L. When
+ j==0, we're processing insn2's operands, so we
+ want to mark the operand if insn2 is *not* in the
+ R container. When j==1, we're processing insn1's
+ operands, so we want to mark the operand if insn2
+ *is* in the R container. Note that, if two
+ instructions are identical, we're never going to
+ swap them, so the test is safe. */
+ && j == ((insn & 0x7fff) == insn2))
+ fx->fix[i].operand |= 1024;
- save = input_line_pointer;
- input_line_pointer = op_end;
- *opcode = find_opcode (*opcode, myops);
- if (*opcode == 0)
- return -1;
- input_line_pointer = save;
+ if (fx->fix[i].reloc == BFD_RELOC_D10V_18)
+ fx->fix[i].operand |= 4096;
- insn = build_insn ((*opcode), myops, 0);
- return (insn);
+ fix_new_exp (frag_now,
+ where,
+ fx->fix[i].size,
+ &(fx->fix[i].exp),
+ fx->fix[i].pcrel,
+ fx->fix[i].operand|2048);
+ }
+ }
+ fx->fc = 0;
+ fx = fx->next;
+ }
+ return 0;
}
+/* 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 D10V, it
+ mostly handles the special VLIW parsing and packing and leaves the
+ difficult stuff to do_assemble(). */
+
+static unsigned long prev_insn;
+static struct d10v_opcode *prev_opcode = 0;
+static subsegT prev_subseg;
+static segT prev_seg = 0;
+
/* Find the symbol which has the same name as the register in exp. */
static symbolS *
-find_symbol_matching_register (exp)
- expressionS *exp;
+find_symbol_matching_register (expressionS *exp)
{
int i;
the operands to choose the correct opcode. */
static struct d10v_opcode *
-find_opcode (opcode, myops)
- struct d10v_opcode *opcode;
- expressionS myops[];
+find_opcode (struct d10v_opcode *opcode, expressionS myops[])
{
int i, match;
struct d10v_opcode *next_opcode;
for (i = 0; opcode->operands[i + 1]; i++)
{
int bits = d10v_operands[next_opcode->operands[opnum]].bits;
- int flags = d10v_operands[next_opcode->operands[opnum]].flags;
+
+ flags = d10v_operands[next_opcode->operands[opnum]].flags;
+
if (flags & OPERAND_ADDR)
bits += 2;
unsigned long current_position;
unsigned long symbol_position;
unsigned long value;
- boolean found_symbol;
+ bfd_boolean found_symbol;
/* Calculate the address of the current instruction
and the address of the symbol. Do this by summing
the offsets of previous frags until we reach the
frag containing the symbol, and the current frag. */
sym_frag = symbol_get_frag (myops[opnum].X_add_symbol);
- found_symbol = false;
+ found_symbol = FALSE;
- current_position =
- obstack_next_free (&frchain_now->frch_obstack)
- - frag_now->fr_literal;
+ current_position = frag_now_fix_octets ();
symbol_position = S_GET_VALUE (myops[opnum].X_add_symbol);
for (f = frchain_now->frch_root; f; f = f->fr_next)
current_position += f->fr_fix + f->fr_offset;
if (f == sym_frag)
- found_symbol = true;
+ found_symbol = TRUE;
if (! found_symbol)
symbol_position += f->fr_fix + f->fr_offset;
opcode = next_opcode;
}
else
- {
- /* Not a constant, so use a long instruction. */
- opcode += 2;
- }
+ /* Not a constant, so use a long instruction. */
+ opcode += 2;
}
match = 0;
-
+
/* Now search the opcode table table for one with operands
that matches what we've got. */
while (!match)
break;
}
- /* Unfortunatly, for the indirect operand in instructions such
- as ``ldb r1, @(c,r14)'' this function can be passed
- X_op == O_register (because 'c' is a valid register name).
- However we cannot just ignore the case when X_op == O_register
- but flags & OPERAND_REG is null, so we check to see if a symbol
- of the same name as the register exists. If the symbol does
- exist, then the parser was unable to distinguish the two cases
+ /* Unfortunately, for the indirect operand in instructions such
+ as ``ldb r1, @(c,r14)'' this function can be passed
+ X_op == O_register (because 'c' is a valid register name).
+ However we cannot just ignore the case when X_op == O_register
+ but flags & OPERAND_REG is null, so we check to see if a symbol
+ of the same name as the register exists. If the symbol does
+ exist, then the parser was unable to distinguish the two cases
and we fix things here. (Ref: PR14826) */
if (!(flags & OPERAND_REG) && (X_op == O_register))
{
symbolS * sym;
-
+
sym = find_symbol_matching_register (& myops[i]);
if (sym != NULL)
if (!match)
{
as_bad (_("bad opcode or operands"));
- return (0);
+ return 0;
}
/* Check that all registers that are required to be even are.
return opcode;
}
+/* Assemble a single instruction.
+ Return an opcode, or -1 (an invalid opcode) on error. */
+
+static unsigned long
+do_assemble (char *str, struct d10v_opcode **opcode)
+{
+ unsigned char *op_start, *op_end;
+ char *save;
+ char name[20];
+ int nlen = 0;
+ expressionS myops[6];
+
+ /* Drop leading whitespace. */
+ while (*str == ' ')
+ str++;
+
+ /* Find the opcode end. */
+ for (op_start = op_end = (unsigned char *) str;
+ *op_end && !is_end_of_line[*op_end] && *op_end != ' ';
+ op_end++)
+ {
+ name[nlen] = TOLOWER (op_start[nlen]);
+ nlen++;
+ if (nlen == sizeof (name) - 1)
+ break;
+ }
+ name[nlen] = 0;
+
+ if (nlen == 0)
+ return -1;
+
+ /* Find the first opcode with the proper name. */
+ *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name);
+ if (*opcode == NULL)
+ return -1;
+
+ save = input_line_pointer;
+ input_line_pointer = (char *) op_end;
+ *opcode = find_opcode (*opcode, myops);
+ if (*opcode == 0)
+ return -1;
+ input_line_pointer = save;
+
+ return build_insn ((*opcode), myops, 0);
+}
+
/* If while processing a fixup, a reloc really needs to be created.
Then it is done here. */
arelent *
-tc_gen_reloc (seg, fixp)
- asection *seg ATTRIBUTE_UNUSED;
- fixS *fixp;
+tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
{
arelent *reloc;
- reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
return NULL;
}
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
reloc->address = fixp->fx_offset;
- reloc->addend = fixp->fx_addnumber;
+ reloc->addend = 0;
return reloc;
}
int
-md_estimate_size_before_relax (fragp, seg)
- fragS *fragp ATTRIBUTE_UNUSED;
- asection *seg ATTRIBUTE_UNUSED;
+md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
+ asection *seg ATTRIBUTE_UNUSED)
{
abort ();
return 0;
}
long
-md_pcrel_from_section (fixp, sec)
- fixS *fixp;
- segT sec;
+md_pcrel_from_section (fixS *fixp, segT sec)
{
if (fixp->fx_addsy != (symbolS *) NULL
&& (!S_IS_DEFINED (fixp->fx_addsy)
}
void
-md_apply_fix3 (fixP, valP, seg)
- fixS *fixP;
- valueT * valP;
- segT seg ATTRIBUTE_UNUSED;
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
char *where;
unsigned long insn;
- long value = * (long *) valP;
+ long value = *valP;
int op_type;
int left = 0;
if (fixP->fx_addsy == (symbolS *) NULL)
fixP->fx_done = 1;
- else if (fixP->fx_pcrel)
- ;
-
- else
- {
- value = fixP->fx_offset;
-
- if (fixP->fx_subsy != (symbolS *) NULL)
- {
- if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
- value -= S_GET_VALUE (fixP->fx_subsy);
- else
- {
- /* We don't actually support subtracting a symbol. */
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("expression too complex"));
- }
- }
- }
+ /* We don't actually support subtracting a symbol. */
+ if (fixP->fx_subsy != (symbolS *) NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
op_type = fixP->fx_r_type;
if (op_type & 2048)
symbol, then ignore the offset.
XXX - Do we have to worry about branches to a symbol + offset ? */
if (fixP->fx_addsy != NULL
- && S_IS_EXTERN (fixP->fx_addsy) )
+ && S_IS_EXTERNAL (fixP->fx_addsy) )
{
segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
segment_info_type *segf = seg_info(fseg);
if ( segf && segf->sym != fixP->fx_addsy)
value = 0;
}
- /* Drop through. */
+ /* Fall through. */
case BFD_RELOC_D10V_18:
/* Instruction addresses are always right-shifted by 2. */
value >>= AT_WORD_RIGHT_SHIFT;
rep = (struct d10v_opcode *) hash_find (d10v_hash, "rep");
repi = (struct d10v_opcode *) hash_find (d10v_hash, "repi");
if ((insn & FM11) == FM11
- && ((repi != NULL
+ && ((repi != NULL
&& (insn & repi->mask) == (unsigned) repi->opcode)
- || (rep != NULL
+ || (rep != NULL
&& (insn & rep->mask) == (unsigned) rep->opcode))
&& value < 4)
as_fatal
case BFD_RELOC_16:
bfd_putb16 ((bfd_vma) value, (unsigned char *) where);
break;
+ case BFD_RELOC_8:
+ *where = value;
+ break;
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
NOTE: invoked by various macros such as md_cleanup: see. */
int
-d10v_cleanup ()
+d10v_cleanup (void)
{
segT seg;
subsegT subseg;
return 1;
}
+void
+d10v_frob_label (symbolS *lab)
+{
+ d10v_cleanup ();
+ symbol_set_frag (lab, frag_now);
+ S_SET_VALUE (lab, (valueT) frag_now_fix ());
+ dwarf2_emit_label (lab);
+}
+
/* Like normal .word, except support @word.
Clobbers input_line_pointer, checks end-of-line. */
static void
-d10v_dot_word (dummy)
- int dummy ATTRIBUTE_UNUSED;
+d10v_dot_word (int dummy ATTRIBUTE_UNUSED)
{
expressionS exp;
char *p;
From expr.c. */
void
-md_operand (expressionP)
- expressionS *expressionP;
+md_operand (expressionS *expressionP)
{
if (*input_line_pointer == '#' && ! do_not_ignore_hash)
{
}
}
-boolean
-d10v_fix_adjustable (fixP)
- fixS *fixP;
+bfd_boolean
+d10v_fix_adjustable (fixS *fixP)
{
- if (fixP->fx_addsy == NULL)
- return 1;
-
- /* Prevent all adjustments to global and weak symbols or symbols in
- merge sections. */
- if ((S_IS_EXTERN (fixP->fx_addsy)
- || (S_IS_WEAK (fixP->fx_addsy))
- || (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0))
- return 0;
-
/* We need the symbol name for the VTABLE entries. */
if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 1;
}
-int
-d10v_force_relocation (fixp)
- fixS *fixp;
+/* The target specific pseudo-ops which we support. */
+const pseudo_typeS md_pseudo_table[] =
{
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- return 1;
+ { "word", d10v_dot_word, 2 },
+ { NULL, NULL, 0 }
+};
- return 0;
+void
+md_assemble (char *str)
+{
+ /* etype is saved extype. For multi-line instructions. */
+ packing_type extype = PACK_UNSPEC; /* Parallel, etc. */
+ struct d10v_opcode *opcode;
+ unsigned long insn;
+ char *str2;
+
+ if (etype == PACK_UNSPEC)
+ {
+ /* Look for the special multiple instruction separators. */
+ str2 = strstr (str, "||");
+ if (str2)
+ extype = PACK_PARALLEL;
+ else
+ {
+ str2 = strstr (str, "->");
+ if (str2)
+ extype = PACK_LEFT_RIGHT;
+ else
+ {
+ str2 = strstr (str, "<-");
+ if (str2)
+ extype = PACK_RIGHT_LEFT;
+ }
+ }
+
+ /* str2 points to the separator, if there is one. */
+ if (str2)
+ {
+ *str2 = 0;
+
+ /* If two instructions are present and we already have one saved,
+ then first write out the saved one. */
+ d10v_cleanup ();
+
+ /* Assemble first instruction and save it. */
+ prev_insn = do_assemble (str, &prev_opcode);
+ prev_seg = now_seg;
+ prev_subseg = now_subseg;
+ if (prev_insn == (unsigned long) -1)
+ as_fatal (_("can't find previous opcode "));
+ fixups = fixups->next;
+ str = str2 + 2;
+ }
+ }
+
+ insn = do_assemble (str, &opcode);
+ if (insn == (unsigned long) -1)
+ {
+ if (extype != PACK_UNSPEC)
+ etype = extype;
+ else
+ as_bad (_("could not assemble: %s"), str);
+ return;
+ }
+
+ if (etype != PACK_UNSPEC)
+ {
+ extype = etype;
+ etype = PACK_UNSPEC;
+ }
+
+ /* If this is a long instruction, write it and any previous short
+ instruction. */
+ if (opcode->format & LONG_OPCODE)
+ {
+ if (extype != PACK_UNSPEC)
+ as_fatal (_("Unable to mix instructions as specified"));
+ d10v_cleanup ();
+ write_long (insn, fixups);
+ prev_opcode = NULL;
+ return;
+ }
+
+ if (prev_opcode
+ && prev_seg
+ && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
+ d10v_cleanup ();
+
+ if (prev_opcode
+ && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype,
+ fixups)))
+ {
+ /* No instructions saved. */
+ prev_opcode = NULL;
+ }
+ else
+ {
+ if (extype != PACK_UNSPEC)
+ as_fatal (_("Unable to mix instructions as specified"));
+ /* Save last instruction so it may be packed on next pass. */
+ prev_opcode = opcode;
+ prev_insn = insn;
+ prev_seg = now_seg;
+ prev_subseg = now_subseg;
+ fixups = fixups->next;
+ }
}
+