Add support for parallel instructions.

This commit is contained in:
Nick Clifton
1998-01-15 01:58:34 +00:00
parent df5b318730
commit ebde3f6235
3 changed files with 429 additions and 228 deletions

View File

@ -1,3 +1,9 @@
Wed Jan 14 17:52:33 1998 Nick Clifton <nickc@cygnus.com>
* config/tc-m32r.c (md_assemble): Add support for parsing parallel
instructions.
* cgen.c: Formatting changes to improve readability.
Wed Jan 14 15:41:41 1998 Jeffrey A Law (law@cygnus.com) Wed Jan 14 15:41:41 1998 Jeffrey A Law (law@cygnus.com)
* config/tc-mips.c (macro): Rework division code to avoid unfilled * config/tc-mips.c (macro): Rework division code to avoid unfilled

View File

@ -30,13 +30,13 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
void void
cgen_asm_record_register (name, number) cgen_asm_record_register (name, number)
char *name; char * name;
int number; int number;
{ {
/* Use symbol_create here instead of symbol_new so we don't try to /* Use symbol_create here instead of symbol_new so we don't try to
output registers into the object file's symbol table. */ output registers into the object file's symbol table. */
symbol_table_insert (symbol_create (name, reg_section, symbol_table_insert (symbol_create (name, reg_section,
number, &zero_address_frag)); number, & zero_address_frag));
} }
/* We need to keep a list of fixups. We can't simply generate them as /* We need to keep a list of fixups. We can't simply generate them as
@ -59,7 +59,7 @@ struct fixup
#define MAX_FIXUPS 5 #define MAX_FIXUPS 5
static struct fixup fixups[MAX_FIXUPS]; static struct fixup fixups [MAX_FIXUPS];
static int num_fixups; static int num_fixups;
/* Prepare to parse an instruction. /* Prepare to parse an instruction.
@ -76,15 +76,15 @@ cgen_asm_init_parse ()
void void
cgen_queue_fixup (opindex, opinfo, expP) cgen_queue_fixup (opindex, opinfo, expP)
int opindex; int opindex;
expressionS *expP; expressionS * expP;
{ {
/* We need to generate a fixup for this expression. */ /* We need to generate a fixup for this expression. */
if (num_fixups >= MAX_FIXUPS) if (num_fixups >= MAX_FIXUPS)
as_fatal ("too many fixups"); as_fatal ("too many fixups");
fixups[num_fixups].exp = *expP; fixups[num_fixups].exp = * expP;
fixups[num_fixups].opindex = opindex; fixups[num_fixups].opindex = opindex;
fixups[num_fixups].opinfo = opinfo; fixups[num_fixups].opinfo = opinfo;
++num_fixups; ++ num_fixups;
} }
/* Default routine to record a fixup. /* Default routine to record a fixup.
@ -102,16 +102,16 @@ cgen_queue_fixup (opindex, opinfo, expP)
fixS * fixS *
cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
fragS *frag; fragS * frag;
int where; int where;
const CGEN_INSN *insn; const CGEN_INSN * insn;
int length; int length;
const CGEN_OPERAND *operand; const CGEN_OPERAND * operand;
int opinfo; int opinfo;
symbolS *symbol; symbolS * symbol;
offsetT offset; offsetT offset;
{ {
fixS *fixP; fixS * fixP;
/* It may seem strange to use operand->attrs and not insn->attrs here, /* It may seem strange to use operand->attrs and not insn->attrs here,
but it is the operand that has a pc relative relocation. */ but it is the operand that has a pc relative relocation. */
@ -140,15 +140,15 @@ cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset)
fixS * fixS *
cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
fragS *frag; fragS * frag;
int where; int where;
const CGEN_INSN *insn; const CGEN_INSN * insn;
int length; int length;
const CGEN_OPERAND *operand; const CGEN_OPERAND * operand;
int opinfo; int opinfo;
expressionS *exp; expressionS * exp;
{ {
fixS *fixP; fixS * fixP;
/* It may seem strange to use operand->attrs and not insn->attrs here, /* It may seem strange to use operand->attrs and not insn->attrs here,
but it is the operand that has a pc relative relocation. */ but it is the operand that has a pc relative relocation. */
@ -179,21 +179,21 @@ static jmp_buf expr_jmp_buf;
const char * const char *
cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP) cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
enum cgen_parse_operand_type want; enum cgen_parse_operand_type want;
const char **strP; const char ** strP;
int opindex; int opindex;
int opinfo; int opinfo;
enum cgen_parse_operand_result *resultP; enum cgen_parse_operand_result * resultP;
bfd_vma *valueP; bfd_vma * valueP;
{ {
#ifdef __STDC__ #ifdef __STDC__
/* These is volatile to survive the setjmp. */ /* These is volatile to survive the setjmp. */
char * volatile hold; char * volatile hold;
enum cgen_parse_operand_result * volatile resultP_1; enum cgen_parse_operand_result * volatile resultP_1;
#else #else
static char *hold; static char * hold;
static enum cgen_parse_operand_result *resultP_1; static enum cgen_parse_operand_result * resultP_1;
#endif #endif
const char *errmsg = NULL; const char * errmsg = NULL;
expressionS exp; expressionS exp;
if (want == CGEN_PARSE_OPERAND_INIT) if (want == CGEN_PARSE_OPERAND_INIT)
@ -204,20 +204,20 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
resultP_1 = resultP; resultP_1 = resultP;
hold = input_line_pointer; hold = input_line_pointer;
input_line_pointer = (char *) *strP; input_line_pointer = (char *) * strP;
/* We rely on md_operand to longjmp back to us. /* We rely on md_operand to longjmp back to us.
This is done via cgen_md_operand. */ This is done via cgen_md_operand. */
if (setjmp (expr_jmp_buf) != 0) if (setjmp (expr_jmp_buf) != 0)
{ {
input_line_pointer = (char *) hold; input_line_pointer = (char *) hold;
*resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR; * resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR;
return "illegal operand"; return "illegal operand";
} }
expression (&exp); expression (& exp);
*strP = input_line_pointer; * strP = input_line_pointer;
input_line_pointer = hold; input_line_pointer = hold;
/* FIXME: Need to check `want'. */ /* FIXME: Need to check `want'. */
@ -226,24 +226,24 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
{ {
case O_illegal : case O_illegal :
errmsg = "illegal operand"; errmsg = "illegal operand";
*resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; * resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
break; break;
case O_absent : case O_absent :
errmsg = "missing operand"; errmsg = "missing operand";
*resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; * resultP = CGEN_PARSE_OPERAND_RESULT_ERROR;
break; break;
case O_constant : case O_constant :
*valueP = exp.X_add_number; * valueP = exp.X_add_number;
*resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER; * resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER;
break; break;
case O_register : case O_register :
*valueP = exp.X_add_number; * valueP = exp.X_add_number;
*resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER; * resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER;
break; break;
default : default :
cgen_queue_fixup (opindex, opinfo, &exp); cgen_queue_fixup (opindex, opinfo, & exp);
*valueP = 0; * valueP = 0;
*resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; * resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED;
break; break;
} }
@ -257,7 +257,7 @@ cgen_parse_operand (want, strP, opindex, opinfo, resultP, valueP)
void void
cgen_md_operand (expressionP) cgen_md_operand (expressionP)
expressionS *expressionP; expressionS * expressionP;
{ {
longjmp (expr_jmp_buf, 1); longjmp (expr_jmp_buf, 1);
} }
@ -268,12 +268,13 @@ cgen_md_operand (expressionP)
void void
cgen_asm_finish_insn (insn, buf, length) cgen_asm_finish_insn (insn, buf, length)
const CGEN_INSN *insn; const CGEN_INSN * insn;
cgen_insn_t *buf; cgen_insn_t * buf;
unsigned int length; unsigned int length;
{ {
int i, relax_operand; int i;
char *f; int relax_operand;
char * f;
unsigned int byte_len = length / 8; unsigned int byte_len = length / 8;
/* ??? Target foo issues various warnings here, so one might want to provide /* ??? Target foo issues various warnings here, so one might want to provide
@ -299,7 +300,7 @@ cgen_asm_finish_insn (insn, buf, length)
/* Scan the fixups for the operand affected by relaxing /* Scan the fixups for the operand affected by relaxing
(i.e. the branch address). */ (i.e. the branch address). */
for (i = 0; i < num_fixups; ++i) for (i = 0; i < num_fixups; ++ i)
{ {
if (CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex], if (CGEN_OPERAND_ATTR (& CGEN_SYM (operand_table) [fixups[i].opindex],
CGEN_OPERAND_RELAX) != 0) CGEN_OPERAND_RELAX) != 0)
@ -313,7 +314,7 @@ cgen_asm_finish_insn (insn, buf, length)
if (relax_operand != -1) if (relax_operand != -1)
{ {
int max_len; int max_len;
fragS *old_frag; fragS * old_frag;
#ifdef TC_CGEN_MAX_RELAX #ifdef TC_CGEN_MAX_RELAX
max_len = TC_CGEN_MAX_RELAX (insn, byte_len); max_len = TC_CGEN_MAX_RELAX (insn, byte_len);
@ -323,10 +324,13 @@ cgen_asm_finish_insn (insn, buf, length)
/* Ensure variable part and fixed part are in same fragment. */ /* Ensure variable part and fixed part are in same fragment. */
/* FIXME: Having to do this seems like a hack. */ /* FIXME: Having to do this seems like a hack. */
frag_grow (max_len); frag_grow (max_len);
/* Allocate space for the fixed part. */ /* Allocate space for the fixed part. */
f = frag_more (byte_len); f = frag_more (byte_len);
/* Create a relaxable fragment for this instruction. */ /* Create a relaxable fragment for this instruction. */
old_frag = frag_now; old_frag = frag_now;
frag_var (rs_machine_dependent, frag_var (rs_machine_dependent,
max_len - byte_len /* max chars */, max_len - byte_len /* max chars */,
0 /* variable part already allocated */, 0 /* variable part already allocated */,
@ -336,6 +340,7 @@ cgen_asm_finish_insn (insn, buf, length)
fixups[relax_operand].exp.X_add_symbol, fixups[relax_operand].exp.X_add_symbol,
fixups[relax_operand].exp.X_add_number, fixups[relax_operand].exp.X_add_number,
f); f);
/* Record the operand number with the fragment so md_convert_frag /* Record the operand number with the fragment so md_convert_frag
can use cgen_md_record_fixup to record the appropriate reloc. */ can use cgen_md_record_fixup to record the appropriate reloc. */
old_frag->fr_cgen.insn = insn; old_frag->fr_cgen.insn = insn;
@ -352,15 +357,15 @@ cgen_asm_finish_insn (insn, buf, length)
{ {
case 16: case 16:
if (cgen_big_endian_p) if (cgen_big_endian_p)
bfd_putb16 ((bfd_vma) *buf, f); bfd_putb16 ((bfd_vma) * buf, f);
else else
bfd_putl16 ((bfd_vma) *buf, f); bfd_putl16 ((bfd_vma) * buf, f);
break; break;
case 32: case 32:
if (cgen_big_endian_p) if (cgen_big_endian_p)
bfd_putb32 ((bfd_vma) *buf, f); bfd_putb32 ((bfd_vma) * buf, f);
else else
bfd_putl32 ((bfd_vma) *buf, f); bfd_putl32 ((bfd_vma) * buf, f);
break; break;
default: default:
abort (); abort ();
@ -388,7 +393,7 @@ cgen_asm_finish_insn (insn, buf, length)
insn, length, insn, length,
& CGEN_SYM (operand_table) [fixups[i].opindex], & CGEN_SYM (operand_table) [fixups[i].opindex],
fixups[i].opinfo, fixups[i].opinfo,
&fixups[i].exp); & fixups[i].exp);
} }
} }
@ -406,11 +411,11 @@ cgen_asm_finish_insn (insn, buf, length)
int int
cgen_md_apply_fix3 (fixP, valueP, seg) cgen_md_apply_fix3 (fixP, valueP, seg)
fixS *fixP; fixS * fixP;
valueT *valueP; valueT * valueP;
segT seg; segT seg;
{ {
char *where = fixP->fx_frag->fr_literal + fixP->fx_where; char * where = fixP->fx_frag->fr_literal + fixP->fx_where;
valueT value; valueT value;
/* FIXME FIXME FIXME: The value we are passed in *valuep includes /* FIXME FIXME FIXME: The value we are passed in *valuep includes
@ -426,11 +431,11 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
if (fixP->fx_addsy == (symbolS *) NULL) if (fixP->fx_addsy == (symbolS *) NULL)
{ {
value = *valueP; value = * valueP;
fixP->fx_done = 1; fixP->fx_done = 1;
} }
else if (fixP->fx_pcrel) else if (fixP->fx_pcrel)
value = *valueP; value = * valueP;
else else
{ {
value = fixP->fx_offset; value = fixP->fx_offset;
@ -450,11 +455,11 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
{ {
int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
const CGEN_OPERAND *operand = & CGEN_SYM (operand_table) [opindex]; const CGEN_OPERAND * operand = & CGEN_SYM (operand_table) [opindex];
const char *errmsg; const char * errmsg;
bfd_reloc_code_real_type reloc_type; bfd_reloc_code_real_type reloc_type;
CGEN_FIELDS fields; CGEN_FIELDS fields;
const CGEN_INSN *insn = (CGEN_INSN *) fixP->tc_fix_data.insn; const CGEN_INSN * insn = (CGEN_INSN *) fixP->tc_fix_data.insn;
/* If the reloc has been fully resolved finish the operand here. */ /* If the reloc has been fully resolved finish the operand here. */
/* FIXME: This duplicates the capabilities of code in BFD. */ /* FIXME: This duplicates the capabilities of code in BFD. */
@ -465,12 +470,12 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
{ {
/* This may seem like overkill, and using bfd_install_relocation or /* This may seem like overkill, and using bfd_install_relocation or
some such may be preferable, but this is simple. */ some such may be preferable, but this is simple. */
CGEN_FIELDS_BITSIZE (&fields) = CGEN_INSN_BITSIZE (insn); CGEN_FIELDS_BITSIZE (& fields) = CGEN_INSN_BITSIZE (insn);
CGEN_SYM (set_operand) (opindex, &value, &fields); CGEN_SYM (set_operand) (opindex, & value, & fields);
errmsg = CGEN_SYM (validate_operand) (opindex, &fields); errmsg = CGEN_SYM (validate_operand) (opindex, & fields);
if (errmsg) if (errmsg)
as_warn_where (fixP->fx_file, fixP->fx_line, "%s\n", errmsg); as_warn_where (fixP->fx_file, fixP->fx_line, "%s\n", errmsg);
CGEN_SYM (insert_operand) (opindex, &fields, where); CGEN_SYM (insert_operand) (opindex, & fields, where);
} }
if (fixP->fx_done) if (fixP->fx_done)
@ -533,10 +538,10 @@ cgen_md_apply_fix3 (fixP, valueP, seg)
arelent * arelent *
cgen_tc_gen_reloc (section, fixP) cgen_tc_gen_reloc (section, fixP)
asection *section; asection * section;
fixS *fixP; fixS * fixP;
{ {
arelent *reloc; arelent * reloc;
reloc = (arelent *) bfd_alloc (stdoutput, sizeof (arelent)); reloc = (arelent *) bfd_alloc (stdoutput, sizeof (arelent));
@ -551,7 +556,7 @@ cgen_tc_gen_reloc (section, fixP)
assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
reloc->sym_ptr_ptr = &fixP->fx_addsy->bsym; reloc->sym_ptr_ptr = & fixP->fx_addsy->bsym;
reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
reloc->addend = fixP->fx_addnumber; reloc->addend = fixP->fx_addnumber;

View File

@ -24,9 +24,12 @@
#include "subsegs.h" #include "subsegs.h"
#include "cgen-opc.h" #include "cgen-opc.h"
#include "../../opcodes/m32r-asm.c"
#include "../../opcodes/m32r-asm.in"
/* Non-null if last insn was a 16 bit insn on a 32 bit boundary /* Non-null if last insn was a 16 bit insn on a 32 bit boundary
(i.e. was the first of two 16 bit insns). */ (i.e. was the first of two 16 bit insns). */
static const CGEN_INSN *prev_insn = NULL; static const CGEN_INSN * prev_insn = NULL;
/* Non-zero if we've seen a relaxable insn since the last 32 bit /* Non-zero if we've seen a relaxable insn since the last 32 bit
alignment request. */ alignment request. */
@ -40,12 +43,11 @@ static int m32r_relax;
/* If non-NULL, pointer to cpu description file to read. /* If non-NULL, pointer to cpu description file to read.
This allows runtime additions to the assembler. */ This allows runtime additions to the assembler. */
static char *m32r_cpu_desc; static char * m32r_cpu_desc;
/* start-sanitize-m32rx */ /* start-sanitize-m32rx */
/* Non-zero if -m32rx has been specified, in which case support for the /* Non-zero if -m32rx has been specified, in which case support for the
extended M32RX instruction set should be enabled. */ extended M32RX instruction set should be enabled. */
/* Indicates the target BFD machine number. */
static int enable_m32rx = 0; static int enable_m32rx = 0;
/* end-sanitize-m32rx */ /* end-sanitize-m32rx */
@ -73,17 +75,15 @@ const char FLT_CHARS[] = "dD";
struct m32r_hi_fixup struct m32r_hi_fixup
{ {
/* Next HI fixup. */ struct m32r_hi_fixup * next; /* Next HI fixup. */
struct m32r_hi_fixup *next; fixS * fixp; /* This fixup. */
/* This fixup. */ segT seg; /* The section this fixup is in. */
fixS *fixp;
/* The section this fixup is in. */
segT seg;
}; };
/* The list of unmatched HI relocs. */ /* The list of unmatched HI relocs. */
static struct m32r_hi_fixup *m32r_hi_fixup_list; static struct m32r_hi_fixup * m32r_hi_fixup_list;
static void m32r_record_hi16 PARAMS ((int, fixS *, segT seg)); static void m32r_record_hi16 PARAMS ((int, fixS *, segT seg));
@ -95,11 +95,12 @@ allow_m32rx (int on)
enable_m32rx = on; enable_m32rx = on;
if (stdoutput != NULL) if (stdoutput != NULL)
bfd_set_arch_mach (stdoutput, TARGET_ARCH, enable_m32rx ? bfd_mach_m32rx : bfd_mach_m32r); bfd_set_arch_mach (stdoutput, TARGET_ARCH,
enable_m32rx ? bfd_mach_m32rx : bfd_mach_m32r);
} }
/* end-sanitize-m32rx */ /* end-sanitize-m32rx */
const char *md_shortopts = ""; const char * md_shortopts = "";
struct option md_longopts[] = struct option md_longopts[] =
{ {
@ -117,12 +118,12 @@ struct option md_longopts[] =
{NULL, no_argument, NULL, 0} {NULL, no_argument, NULL, 0}
}; };
size_t md_longopts_size = sizeof(md_longopts); size_t md_longopts_size = sizeof (md_longopts);
int int
md_parse_option (c, arg) md_parse_option (c, arg)
int c; int c;
char *arg; char * arg;
{ {
switch (c) switch (c)
{ {
@ -148,7 +149,7 @@ md_parse_option (c, arg)
void void
md_show_usage (stream) md_show_usage (stream)
FILE *stream; FILE * stream;
{ {
fprintf (stream, "M32R/X options:\n"); fprintf (stream, "M32R/X options:\n");
/* start-sanitize-m32rx */ /* start-sanitize-m32rx */
@ -196,11 +197,11 @@ const pseudo_typeS md_pseudo_table[] =
int int
m32r_do_align (n, fill, len, max) m32r_do_align (n, fill, len, max)
int n; int n;
const char *fill; const char * fill;
int len; int len;
int max; int max;
{ {
if ((fill == NULL || (*fill == 0 && len == 1)) if ((fill == NULL || (* fill == 0 && len == 1))
&& (now_seg->flags & SEC_CODE) != 0 && (now_seg->flags & SEC_CODE) != 0
/* Only do this special handling if aligning to at least a /* Only do this special handling if aligning to at least a
4 byte boundary. */ 4 byte boundary. */
@ -224,7 +225,8 @@ m32r_do_align (n, fill, len, max)
nops. */ nops. */
if (n > 2) if (n > 2)
{ {
static const unsigned char multi_nop_pattern[] = { 0x70, 0x00, 0xf0, 0x00 }; static const unsigned char multi_nop_pattern[] =
{ 0x70, 0x00, 0xf0, 0x00 };
frag_align_pattern (n, multi_nop_pattern, sizeof multi_nop_pattern, frag_align_pattern (n, multi_nop_pattern, sizeof multi_nop_pattern,
max ? max - 2 : 0); max ? max - 2 : 0);
} }
@ -238,7 +240,7 @@ static void
assemble_nop (opcode) assemble_nop (opcode)
int opcode; int opcode;
{ {
char *f = frag_more (2); char * f = frag_more (2);
md_number_to_chars (f, opcode, 2); md_number_to_chars (f, opcode, 2);
} }
@ -276,10 +278,14 @@ m32r_fill_insn (done)
{ {
seg = now_seg; seg = now_seg;
subseg = now_subseg; subseg = now_subseg;
subseg_set (prev_seg, prev_subseg); subseg_set (prev_seg, prev_subseg);
fill_insn (0); fill_insn (0);
subseg_set (seg, subseg); subseg_set (seg, subseg);
} }
return 1; return 1;
} }
@ -294,15 +300,17 @@ md_begin ()
/* This is a callback from cgen to gas to parse operands. */ /* This is a callback from cgen to gas to parse operands. */
cgen_parse_operand_fn = cgen_parse_operand; cgen_parse_operand_fn = cgen_parse_operand;
/* Set the machine number and endian. */ /* Set the machine number and endian. */
CGEN_SYM (init_asm) (0 /* mach number */, CGEN_SYM (init_asm) (0 /* mach number */,
target_big_endian ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE); target_big_endian ?
CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
#if 0 /* not supported yet */ #if 0 /* not supported yet */
/* If a runtime cpu description file was provided, parse it. */ /* If a runtime cpu description file was provided, parse it. */
if (m32r_cpu_desc != NULL) if (m32r_cpu_desc != NULL)
{ {
const char *errmsg; const char * errmsg;
errmsg = cgen_read_cpu_file (m32r_cpu_desc); errmsg = cgen_read_cpu_file (m32r_cpu_desc);
if (errmsg != NULL) if (errmsg != NULL)
@ -311,15 +319,17 @@ md_begin ()
#endif #endif
/* Save the current subseg so we can restore it [it's the default one and /* Save the current subseg so we can restore it [it's the default one and
we don't want the initial section to be .sbss. */ we don't want the initial section to be .sbss]. */
seg = now_seg; seg = now_seg;
subseg = now_subseg; subseg = now_subseg;
/* The sbss section is for local .scomm symbols. */ /* The sbss section is for local .scomm symbols. */
sbss_section = subseg_new (".sbss", 0); sbss_section = subseg_new (".sbss", 0);
/* This is copied from perform_an_assembly_pass. */ /* This is copied from perform_an_assembly_pass. */
applicable = bfd_applicable_section_flags (stdoutput); applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, sbss_section, applicable & SEC_ALLOC); bfd_set_section_flags (stdoutput, sbss_section, applicable & SEC_ALLOC);
#if 0 /* What does this do? [see perform_an_assembly_pass] */ #if 0 /* What does this do? [see perform_an_assembly_pass] */
seg_info (bss_section)->bss = 1; seg_info (bss_section)->bss = 1;
#endif #endif
@ -330,49 +340,219 @@ md_begin ()
but with the name .scommon. */ but with the name .scommon. */
scom_section = bfd_com_section; scom_section = bfd_com_section;
scom_section.name = ".scommon"; scom_section.name = ".scommon";
scom_section.output_section = &scom_section; scom_section.output_section = & scom_section;
scom_section.symbol = &scom_symbol; scom_section.symbol = & scom_symbol;
scom_section.symbol_ptr_ptr = &scom_section.symbol; scom_section.symbol_ptr_ptr = & scom_section.symbol;
scom_symbol = *bfd_com_section.symbol; scom_symbol = * bfd_com_section.symbol;
scom_symbol.name = ".scommon"; scom_symbol.name = ".scommon";
scom_symbol.section = &scom_section; scom_symbol.section = & scom_section;
/* start-sanitize-m32rx */ /* start-sanitize-m32rx */
allow_m32rx (enable_m32rx); allow_m32rx (enable_m32rx);
/* end-sanitize-m32rx */ /* end-sanitize-m32rx */
} }
/* Returns non zero if the given instruction writes to a destination register. */
static int
writes_to_dest_reg (insn)
const CGEN_INSN * insn;
{
unsigned char * syntax = CGEN_SYNTAX_STRING (CGEN_INSN_SYNTAX (insn));
unsigned char c;
/* Scan the syntax string looking for a destination register. */
while ((c = (* syntax ++)) != 0)
if (c == 128 + M32R_OPERAND_DR)
break;
return c;
}
/* Returns an integer representing the destination register of
the given insn, or -1 if the insn has no destination. */
static int
get_dest_reg (insn)
const CGEN_INSN * insn;
{
/* XXX to be done. */
return -1;
}
void void
md_assemble (str) md_assemble (str)
char *str; char * str;
{ {
#ifdef CGEN_INT_INSN #ifdef CGEN_INT_INSN
cgen_insn_t buffer[CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)]; cgen_insn_t buffer [CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)];
cgen_insn_t prev_buffer [CGEN_MAX_INSN_SIZE / sizeof (cgen_insn_t)];
#else #else
char buffer[CGEN_MAX_INSN_SIZE]; char buffer [CGEN_MAX_INSN_SIZE];
char prev_buffer [CGEN_MAX_INSN_SIZE];
#endif #endif
CGEN_FIELDS fields; CGEN_FIELDS fields;
const CGEN_INSN *insn; CGEN_FIELDS prev_fields;
char *errmsg; const CGEN_INSN * insn;
char * errmsg;
char * str2 = NULL;
int is_parallel = false;
/* Initialize GAS's cgen interface for a new instruction. */ /* Initialize GAS's cgen interface for a new instruction. */
cgen_asm_init_parse (); cgen_asm_init_parse ();
insn = CGEN_SYM (assemble_insn) (str, &fields, buffer, &errmsg); /* Look for a parallel instruction seperator. */
if ((str2 = strstr (str, "||")) != NULL)
{
char * str3;
* str2 = 0; /* Seperate the two instructions. */
/* If there was a previous 16 bit insn, then fill the following 16 bit slot,
so that the parallel instruction will start on a 32 bit boundary. */
if (prev_insn)
fill_insn (0);
/* Assemble the first instruction. */
prev_insn = CGEN_SYM (assemble_insn) (str, & prev_fields, prev_buffer, & errmsg);
if (! prev_insn)
{
as_bad (errmsg);
return;
}
/* Check to see if this is an allowable parallel insn. */
if (CGEN_INSN_ATTR (prev_insn, CGEN_INSN_PIPE) == PIPE_NONE)
{
as_bad ("instruction '%s' cannot be executed in parallel.", str);
return;
}
/* start-sanitize-m32rx */
if (! enable_m32rx &&
CGEN_INSN_ATTR (prev_insn, CGEN_INSN_MACH) == MACH_M32RX)
{
as_bad ("instruction '%s' is for the M32RX only", str);
return;
}
/* end-sanitize-m32rx */
/* fixups = fixups->next; */
*str2 = '|'; /* Restore the original assembly text, just in case it is needed. */
str3 = str; /* Save the original string pointer. */
str = str2 + 2; /* Advanced past the parsed string. */
str2 = str3; /* Remember the entire string in case it is needed for error messages. */
is_parallel = true;
}
insn = CGEN_SYM (assemble_insn) (str, & fields, buffer, & errmsg);
if (!insn) if (!insn)
{ {
as_bad (errmsg); as_bad (errmsg);
return; return;
} }
if (CGEN_INSN_BITSIZE (insn) == 32) /* start-sanitize-m32rx */
if (! enable_m32rx
&& CGEN_INSN_ATTR (insn, CGEN_INSN_MACH) == (1 << MACH_M32RX))
{
as_bad ("instruction '%s' is for the M32RX only", str);
return;
}
/* end-sanitize-m32rx */
if (is_parallel)
{
/* start-sanitize-m32rx */
if (! enable_m32rx)
{
if (strcmp (prev_insn->name, "nop") != 0
&& strcmp (insn->name, "nop") != 0)
{
as_bad ("'%s': only the NOP instruction can be issued in parallel on the m32r", str2);
return;
}
}
/* end-sanitize-m32rx */
/* Check to see if this is an allowable parallel insn. */
if (CGEN_INSN_ATTR (insn, CGEN_INSN_PIPE) == PIPE_NONE)
{
as_bad ("instruction '%s', cannot be executed in parallel.", str);
return;
}
/* Check to see that the two instructions can be placed in parallel. */
if ((CGEN_INSN_ATTR (insn, CGEN_INSN_PIPE) == CGEN_INSN_ATTR (prev_insn, CGEN_INSN_PIPE))
&& (CGEN_INSN_ATTR (insn, CGEN_INSN_PIPE) != PIPE_OS))
{
as_bad ("'%s': both instructions use the same execution pipeline", str2);
return;
}
#if 0
/* Check that the instructions do not write to the same destination register. */
if (writes_to_dest_reg (insn)
&& writes_to_dest_reg (prev_insn) /* This test is actually redundant. */
&& get_dest_reg (insn) == get_dest_reg (prev_insn))
{
as_bad ("'%s': both instructions write to the same destination register", str2);
return;
}
#endif
/* Force the top bit of the second insn to be set. */
#if 0 /*def CGEN_INT_INSN*/
#define MAKE_PARALLEL(insn) ((insn) |= 0x8000)
switch (CGEN_FIELDS_BITSIZE (& fields))
{
bfd_vma value;
case 16:
if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG)
{
value = bfd_getb16 ((bfd_vma) * buffer);
MAKE_PARALLEL (value);
bfd_putb16 (value, buffer);
}
else
{
value = bfd_getl16 ((bfd_vma) * buffer);
MAKE_PARALLEL (value);
bfd_putl16 (value, buffer);
}
break;
default:
abort ();
}
#else
#define MAKE_PARALLEL(insn) ((insn) |= 0x80)
MAKE_PARALLEL (buffer [CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG ? 0 : 1]);
#endif
/* Generate the parallel instructions */
cgen_asm_finish_insn (prev_insn, prev_buffer, CGEN_FIELDS_BITSIZE (& prev_fields));
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
/* If prev_ins is relaxable (and insn is not), then swap them, so that the test
after the end of this if-then-else section will work. */
if (CGEN_INSN_ATTR (prev_insn, CGEN_INSN_RELAXABLE))
insn = prev_insn;
/* Clear the prev_insn variable, since it only used if the insn was the first
16 bit insn in a 32 bit word. */
prev_insn = NULL;
}
else if (CGEN_INSN_BITSIZE (insn) == 32)
{ {
/* 32 bit insns must live on 32 bit boundaries. */ /* 32 bit insns must live on 32 bit boundaries. */
if (prev_insn || seen_relaxable_p)
{
/* FIXME: If calling fill_insn too many times turns us into a memory /* FIXME: If calling fill_insn too many times turns us into a memory
pig, can we call assemble_nop instead of !seen_relaxable_p? */ pig, can we call assemble_nop instead of !seen_relaxable_p? */
if (prev_insn || seen_relaxable_p)
fill_insn (0); fill_insn (0);
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (&fields)); }
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
} }
else else
{ {
@ -382,7 +562,8 @@ md_assemble (str)
prev_insn = NULL; prev_insn = NULL;
else else
prev_insn = insn; prev_insn = insn;
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (&fields));
cgen_asm_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (& fields));
/* If the insn needs the following one to be on a 32 bit boundary /* If the insn needs the following one to be on a 32 bit boundary
(e.g. subroutine calls), fill this insn's slot. */ (e.g. subroutine calls), fill this insn's slot. */
@ -407,11 +588,11 @@ md_assemble (str)
void void
md_operand (expressionP) md_operand (expressionP)
expressionS *expressionP; expressionS * expressionP;
{ {
if (*input_line_pointer == '#') if (* input_line_pointer == '#')
{ {
input_line_pointer++; input_line_pointer ++;
expression (expressionP); expression (expressionP);
} }
} }
@ -427,7 +608,7 @@ md_section_align (segment, size)
symbolS * symbolS *
md_undefined_symbol (name) md_undefined_symbol (name)
char *name; char * name;
{ {
return 0; return 0;
} }
@ -443,11 +624,11 @@ static void
m32r_scomm (ignore) m32r_scomm (ignore)
int ignore; int ignore;
{ {
register char *name; register char * name;
register char c; register char c;
register char *p; register char * p;
offsetT size; offsetT size;
register symbolS *symbolP; register symbolS * symbolP;
offsetT align; offsetT align;
int align2; int align2;
@ -456,9 +637,9 @@ m32r_scomm (ignore)
/* just after name is now '\0' */ /* just after name is now '\0' */
p = input_line_pointer; p = input_line_pointer;
*p = c; * p = c;
SKIP_WHITESPACE (); SKIP_WHITESPACE ();
if (*input_line_pointer != ',') if (* input_line_pointer != ',')
{ {
as_bad ("Expected comma after symbol-name: rest of line ignored."); as_bad ("Expected comma after symbol-name: rest of line ignored.");
ignore_rest_of_line (); ignore_rest_of_line ();
@ -474,11 +655,11 @@ m32r_scomm (ignore)
} }
/* The third argument to .scomm is the alignment. */ /* The third argument to .scomm is the alignment. */
if (*input_line_pointer != ',') if (* input_line_pointer != ',')
align = 8; align = 8;
else else
{ {
++input_line_pointer; ++ input_line_pointer;
align = get_absolute_expression (); align = get_absolute_expression ();
if (align <= 0) if (align <= 0)
{ {
@ -489,7 +670,7 @@ m32r_scomm (ignore)
/* Convert to a power of 2 alignment. */ /* Convert to a power of 2 alignment. */
if (align) if (align)
{ {
for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2) for (align2 = 0; (align & 1) == 0; align >>= 1, ++ align2)
continue; continue;
if (align != 1) if (align != 1)
{ {
@ -501,9 +682,9 @@ m32r_scomm (ignore)
else else
align2 = 0; align2 = 0;
*p = 0; * p = 0;
symbolP = symbol_find_or_make (name); symbolP = symbol_find_or_make (name);
*p = c; * p = c;
if (S_IS_DEFINED (symbolP)) if (S_IS_DEFINED (symbolP))
{ {
@ -528,7 +709,7 @@ m32r_scomm (ignore)
{ {
segT old_sec = now_seg; segT old_sec = now_seg;
int old_subsec = now_subseg; int old_subsec = now_subseg;
char *pfrag; char * pfrag;
record_alignment (sbss_section, align2); record_alignment (sbss_section, align2);
subseg_set (sbss_section, 0); subseg_set (sbss_section, 0);
@ -539,7 +720,7 @@ m32r_scomm (ignore)
symbolP->sy_frag = frag_now; symbolP->sy_frag = frag_now;
pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size, pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
(char *) 0); (char *) 0);
*pfrag = 0; * pfrag = 0;
S_SET_SIZE (symbolP, size); S_SET_SIZE (symbolP, size);
S_SET_SEGMENT (symbolP, sbss_section); S_SET_SEGMENT (symbolP, sbss_section);
S_CLEAR_EXTERNAL (symbolP); S_CLEAR_EXTERNAL (symbolP);
@ -588,7 +769,7 @@ const relax_typeS md_relax_table[] =
long long
m32r_relax_frag (fragP, stretch) m32r_relax_frag (fragP, stretch)
fragS *fragP; fragS * fragP;
long stretch; long stretch;
{ {
/* Address of branch insn. */ /* Address of branch insn. */
@ -640,11 +821,11 @@ m32r_relax_frag (fragP, stretch)
int int
md_estimate_size_before_relax (fragP, segment) md_estimate_size_before_relax (fragP, segment)
fragS *fragP; fragS * fragP;
segT segment; segT segment;
{ {
int old_fr_fix = fragP->fr_fix; int old_fr_fix = fragP->fr_fix;
char *opcode = fragP->fr_opcode; char * opcode = fragP->fr_opcode;
/* The only thing we have to handle here are symbols outside of the /* The only thing we have to handle here are symbols outside of the
current segment. They may be undefined or in a different segment in current segment. They may be undefined or in a different segment in
@ -678,7 +859,7 @@ md_estimate_size_before_relax (fragP, segment)
frag_wane (fragP); frag_wane (fragP);
#else #else
{ {
const CGEN_INSN *insn; const CGEN_INSN * insn;
int i; int i;
/* Update the recorded insn. /* Update the recorded insn.
@ -717,8 +898,12 @@ md_convert_frag (abfd, sec, fragP)
segT sec; segT sec;
fragS *fragP; fragS *fragP;
{ {
char *opcode, *displacement; char * opcode;
int target_address, opcode_address, extension, addend; char * displacement;
int target_address;
int opcode_address;
int extension;
int addend;
opcode = fragP->fr_opcode; opcode = fragP->fr_opcode;
@ -729,19 +914,19 @@ md_convert_frag (abfd, sec, fragP)
{ {
case 1 : case 1 :
extension = 0; extension = 0;
displacement = &opcode[1]; displacement = & opcode[1];
break; break;
case 2 : case 2 :
opcode[0] |= 0x80; opcode[0] |= 0x80;
extension = 2; extension = 2;
displacement = &opcode[1]; displacement = & opcode[1];
break; break;
case 3 : case 3 :
opcode[2] = opcode[0] | 0x80; opcode[2] = opcode[0] | 0x80;
md_number_to_chars (opcode, PAR_NOP_INSN, 2); md_number_to_chars (opcode, PAR_NOP_INSN, 2);
opcode_address += 2; opcode_address += 2;
extension = 4; extension = 4;
displacement = &opcode[3]; displacement = & opcode[3];
break; break;
default : default :
abort (); abort ();
@ -799,7 +984,7 @@ md_convert_frag (abfd, sec, fragP)
long long
md_pcrel_from_section (fixP, sec) md_pcrel_from_section (fixP, sec)
fixS *fixP; fixS * fixP;
segT sec; segT sec;
{ {
if (fixP->fx_addsy != (symbolS *) NULL if (fixP->fx_addsy != (symbolS *) NULL
@ -820,9 +1005,9 @@ md_pcrel_from_section (fixP, sec)
bfd_reloc_code_real_type bfd_reloc_code_real_type
CGEN_SYM (lookup_reloc) (insn, operand, fixP) CGEN_SYM (lookup_reloc) (insn, operand, fixP)
const CGEN_INSN *insn; const CGEN_INSN * insn;
const CGEN_OPERAND *operand; const CGEN_OPERAND * operand;
fixS *fixP; fixS * fixP;
{ {
switch (CGEN_OPERAND_TYPE (operand)) switch (CGEN_OPERAND_TYPE (operand))
{ {
@ -846,15 +1031,15 @@ CGEN_SYM (lookup_reloc) (insn, operand, fixP)
fixS * fixS *
m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
fragS *frag; fragS * frag;
int where; int where;
const CGEN_INSN *insn; const CGEN_INSN * insn;
int length; int length;
const CGEN_OPERAND *operand; const CGEN_OPERAND * operand;
int opinfo; int opinfo;
expressionS *exp; expressionS * exp;
{ {
fixS *fixP = cgen_record_fixup_exp (frag, where, insn, length, fixS * fixP = cgen_record_fixup_exp (frag, where, insn, length,
operand, opinfo, exp); operand, opinfo, exp);
switch (CGEN_OPERAND_TYPE (operand)) switch (CGEN_OPERAND_TYPE (operand))
@ -875,10 +1060,10 @@ m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
static void static void
m32r_record_hi16 (reloc_type, fixP, seg) m32r_record_hi16 (reloc_type, fixP, seg)
int reloc_type; int reloc_type;
fixS *fixP; fixS * fixP;
segT seg; segT seg;
{ {
struct m32r_hi_fixup *hi_fixup; struct m32r_hi_fixup * hi_fixup;
assert (reloc_type == BFD_RELOC_M32R_HI16_SLO assert (reloc_type == BFD_RELOC_M32R_HI16_SLO
|| reloc_type == BFD_RELOC_M32R_HI16_ULO); || reloc_type == BFD_RELOC_M32R_HI16_ULO);
@ -888,6 +1073,7 @@ m32r_record_hi16 (reloc_type, fixP, seg)
hi_fixup->fixp = fixP; hi_fixup->fixp = fixP;
hi_fixup->seg = now_seg; hi_fixup->seg = now_seg;
hi_fixup->next = m32r_hi_fixup_list; hi_fixup->next = m32r_hi_fixup_list;
m32r_hi_fixup_list = hi_fixup; m32r_hi_fixup_list = hi_fixup;
} }
@ -903,11 +1089,11 @@ m32r_record_hi16 (reloc_type, fixP, seg)
void void
m32r_frob_file () m32r_frob_file ()
{ {
struct m32r_hi_fixup *l; struct m32r_hi_fixup * l;
for (l = m32r_hi_fixup_list; l != NULL; l = l->next) for (l = m32r_hi_fixup_list; l != NULL; l = l->next)
{ {
segment_info_type *seginfo; segment_info_type * seginfo;
int pass; int pass;
assert (FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_M32R_HI16_SLO assert (FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_M32R_HI16_SLO
@ -928,7 +1114,8 @@ m32r_frob_file ()
seginfo = seg_info (l->seg); seginfo = seg_info (l->seg);
for (pass = 0; pass < 2; pass++) for (pass = 0; pass < 2; pass++)
{ {
fixS *f, *prev; fixS * f;
fixS * prev;
prev = NULL; prev = NULL;
for (f = seginfo->fix_root; f != NULL; f = f->fx_next) for (f = seginfo->fix_root; f != NULL; f = f->fx_next)
@ -944,15 +1131,15 @@ m32r_frob_file ()
|| prev->fx_addsy != f->fx_addsy || prev->fx_addsy != f->fx_addsy
|| prev->fx_offset != f->fx_offset)) || prev->fx_offset != f->fx_offset))
{ {
fixS **pf; fixS ** pf;
/* Move l->fixp before f. */ /* Move l->fixp before f. */
for (pf = &seginfo->fix_root; for (pf = &seginfo->fix_root;
*pf != l->fixp; * pf != l->fixp;
pf = &(*pf)->fx_next) pf = & (* pf)->fx_next)
assert (*pf != NULL); assert (* pf != NULL);
*pf = l->fixp->fx_next; * pf = l->fixp->fx_next;
l->fixp->fx_next = f; l->fixp->fx_next = f;
if (prev == NULL) if (prev == NULL)
@ -982,7 +1169,7 @@ m32r_frob_file ()
int int
m32r_force_relocation (fix) m32r_force_relocation (fix)
fixS *fix; fixS * fix;
{ {
if (! m32r_relax) if (! m32r_relax)
return 0; return 0;
@ -995,7 +1182,7 @@ m32r_force_relocation (fix)
void void
md_number_to_chars (buf, val, n) md_number_to_chars (buf, val, n)
char *buf; char * buf;
valueT val; valueT val;
int n; int n;
{ {
@ -1019,11 +1206,12 @@ md_atof (type, litP, sizeP)
char *litP; char *litP;
int *sizeP; int *sizeP;
{ {
int i,prec; int i;
LITTLENUM_TYPE words[MAX_LITTLENUMS]; int prec;
LITTLENUM_TYPE *wordP; LITTLENUM_TYPE words [MAX_LITTLENUMS];
char *t; LITTLENUM_TYPE * wordP;
char *atof_ieee (); char * t;
char * atof_ieee ();
switch (type) switch (type)
{ {
@ -1044,20 +1232,21 @@ md_atof (type, litP, sizeP)
/* FIXME: Some targets allow other format chars for bigger sizes here. */ /* FIXME: Some targets allow other format chars for bigger sizes here. */
default: default:
*sizeP = 0; * sizeP = 0;
return "Bad call to md_atof()"; return "Bad call to md_atof()";
} }
t = atof_ieee (input_line_pointer, type, words); t = atof_ieee (input_line_pointer, type, words);
if (t) if (t)
input_line_pointer = t; input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE); * sizeP = prec * sizeof (LITTLENUM_TYPE);
if (target_big_endian) if (target_big_endian)
{ {
for (i = 0; i < prec; i++) for (i = 0; i < prec; i++)
{ {
md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); md_number_to_chars (litP, (valueT) words[i],
sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE); litP += sizeof (LITTLENUM_TYPE);
} }
} }
@ -1065,7 +1254,8 @@ md_atof (type, litP, sizeP)
{ {
for (i = prec - 1; i >= 0; i--) for (i = prec - 1; i >= 0; i--)
{ {
md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); md_number_to_chars (litP, (valueT) words[i],
sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE); litP += sizeof (LITTLENUM_TYPE);
} }
} }