This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: Merging of various patches for d10v gas
On Tue, 18 Dec 2001, Nick Clifton wrote:
> Hi Alan,
>
> > The following patches are from various fixes that have been
> > floating around and have not been merged back into the head.
>
Here we are.
2001-12-17 Alan Matsuoka <alanm@redhat.com>
From Jeff Knaggs <jknaggs@redhat.com>
* config/tc-d10v.c (check_resource_conflict): New function to
check for resource conflicts.
From Jason Eckhardt <jle@redhat.com>
* config/tc-d10v.c (build_insn): Check for unresolved imm4 or
imm3 fields.
* config/tc-d10v.c (find_opcode): Emit a warning if one of the
reserved control registers is used.
* config/tc-d10v.c (build_insn): Check for unresolved imm4 or
imm3 fields.
From 2001-03-28 Diego Novillo <dnovillo@redhat.com>
* tc-d10v.c (parallel_ok): Prevent packing only if the first
instruction cannot be packed.
From 2001-03-30 Diego Novillo <dnovillo@redhat.com>
* gas/config/tc-d10v.c (check_resource_conflict): Only check
write-write conflicts.
(md_assemble): Reformat introductory comment.
* opcodes/d10v-opc.c (d10v_opcodes): `btsti' does not modify its
arguments.
Index: tc-d10v.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gas/config/tc-d10v.c,v
retrieving revision 1.79
diff -d -c -p -3 -r1.79 tc-d10v.c
*** tc-d10v.c 2001/12/12 07:41:28 1.79
--- tc-d10v.c 2001/12/18 15:03:28
***************
*** 25,31 ****
#include "subsegs.h"
#include "opcode/d10v.h"
#include "elf/ppc.h"
- //#include "read.h"
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
--- 25,30 ----
*************** static unsigned long d10v_insert_operand
*** 99,104 ****
--- 98,105 ----
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 *));
struct option md_longopts[] =
*************** build_insn (opcode, opers, insn)
*** 630,636 ****
if (AT_WORD_P (&opers[i]))
{
! /* Reconize 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. */
--- 631,637 ----
if (AT_WORD_P (&opers[i]))
{
! /* 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. */
*************** build_insn (opcode, opers, insn)
*** 642,649 ****
opers[i].X_add_number = number;
}
else
! fixups->fix[fixups->fc].reloc =
! get_reloc ((struct d10v_operand *) &d10v_operands[opcode->operands[i]]);
if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||
fixups->fix[fixups->fc].reloc == BFD_RELOC_D10V_18)
--- 643,656 ----
opers[i].X_add_number = number;
}
else
! {
! fixups->fix[fixups->fc].reloc =
! get_reloc ((struct d10v_operand *) &d10v_operands[opcode->operands[i]]);
! if ((bits == 3 || bits == 4)
! && fixups->fix[fixups->fc].reloc == 0
! && (flags & OPERAND_NUM))
! as_bad (_("imm4/imm3 field unresolved (undefined symbol?)"));
! }
if (fixups->fix[fixups->fc].reloc == BFD_RELOC_16 ||
fixups->fix[fixups->fc].reloc == BFD_RELOC_D10V_18)
*************** write_2_short (opcode1, insn1, opcode2,
*** 833,838 ****
--- 840,846 ----
}
else
insn = FM00 | (insn1 << 15) | insn2;
+ check_resource_conflict (opcode1, insn1, opcode2, insn2);
break;
case PACK_LEFT_RIGHT:
*************** parallel_ok (op1, insn1, op2, insn2, exe
*** 938,945 ****
/* If this is auto parallization, and either instruction is a branch,
don't parallel. */
! if (exec_type == PACK_UNSPEC
! && (op1->exec_type & ALONE || op2->exec_type & ALONE))
return 0;
/* The idea here is to create two sets of bitmasks (mod and used)
--- 946,952 ----
/* If this is auto parallization, and either instruction is a branch,
don't parallel. */
! 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)
*************** parallel_ok (op1, insn1, op2, insn2, exe
*** 1042,1053 ****
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;
--- 1049,1210 ----
return 0;
}
+ /* Determine if there are any resource conflicts among two manually
+ parallelized instructions. Some of this was lifted from parallel_ok. */
+ static void
+ check_resource_conflict (op1, insn1, op2, insn2)
+ struct d10v_opcode *op1, *op2;
+ unsigned long insn1, insn2;
+ {
+ int i, j, flags, mask, shift, regno;
+ 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;
+ }
+
+
+ /* 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
+ 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 */
+ /* a0-a1 16-17 */
+ /* cr (not psw) 18 */
+ /* psw(other) 19 */
+ /* mem 20 */
+ /* psw(C flag) 21 */
+ /* psw(F0 flag) 22 */
+
+
+ for (j = 0; j < 2; j++)
+ {
+ if (j == 0)
+ {
+ op = op1;
+ ins = insn1;
+ }
+ else
+ {
+ op = op2;
+ ins = insn2;
+ }
+ mod[j] = used[j] = 0;
+ if (op->exec_type & BRANCH_LINK)
+ mod[j] |= 1 << 13;
+
+ for (i = 0; op->operands[i]; i++)
+ {
+ flags = d10v_operands[op->operands[i]].flags;
+ shift = d10v_operands[op->operands[i]].shift;
+ mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits);
+ if (flags & OPERAND_REG)
+ {
+ regno = (ins >> shift) & mask;
+ if (flags & (OPERAND_ACC0 | OPERAND_ACC1))
+ regno += 16;
+ else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */
+ {
+ if (regno == 0)
+ regno = 19;
+ else
+ regno = 18;
+ }
+ else if (flags & OPERAND_FFLAG)
+ regno = 22;
+ else if (flags & OPERAND_CFLAG)
+ regno = 21;
+
+ 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 & RMEM)
+ used[j] |= 1 << 20;
+ else if (op->exec_type & WMEM)
+ mod[j] |= 1 << 20;
+ else if (op->exec_type & RF0)
+ used[j] |= 1 << 22;
+ else if (op->exec_type & WF0)
+ mod[j] |= 1 << 22;
+ 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)"));
+ }
+ }
+ /* 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;
*************** find_opcode (opcode, myops)
*** 1468,1485 ****
if (!(d10v_operands[opcode->operands[i]].flags & OPERAND_REG))
{
myops[i].X_op = O_symbol;
! myops[i].X_add_symbol =
! symbol_find_or_make ((char *) myops[i].X_op_symbol);
myops[i].X_add_number = 0;
myops[i].X_op_symbol = NULL;
}
}
}
return opcode;
}
! /* If while processing a fixup, a reloc really needs to be created.
! Then it is done here. */
arelent *
tc_gen_reloc (seg, fixp)
--- 1625,1650 ----
if (!(d10v_operands[opcode->operands[i]].flags & OPERAND_REG))
{
myops[i].X_op = O_symbol;
! myops[i].X_add_symbol = symbol_find_or_make ((char *)myops[i].X_op_symbol);
myops[i].X_add_number = 0;
myops[i].X_op_symbol = NULL;
}
}
+ if ((d10v_operands[opcode->operands[i]].flags & OPERAND_CONTROL)
+ && (myops[i].X_add_number == OPERAND_CONTROL + 4
+ || myops[i].X_add_number == OPERAND_CONTROL + 5
+ || myops[i].X_add_number == OPERAND_CONTROL + 6
+ || myops[i].X_add_number == OPERAND_CONTROL + 12
+ || myops[i].X_add_number == OPERAND_CONTROL + 13
+ || myops[i].X_add_number == OPERAND_CONTROL + 15))
+ as_warn (_("cr%d is a reserved control register"),
+ myops[i].X_add_number - OPERAND_CONTROL);
}
return opcode;
}
! /* If while processing a fixup, a reloc really needs to be created
! Then it is done here. */
arelent *
tc_gen_reloc (seg, fixp)
*************** md_apply_fix3 (fixP, valP, seg)
*** 1595,1601 ****
--- 1760,1780 ----
case BFD_RELOC_D10V_10_PCREL_L:
case BFD_RELOC_D10V_10_PCREL_R:
case BFD_RELOC_D10V_18_PCREL:
+ /* If the fix is relative to a global symbol, not a section
+ 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) )
+ {
+ 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. */
case BFD_RELOC_D10V_18:
+
/* Instruction addresses are always right-shifted by 2. */
value >>= AT_WORD_RIGHT_SHIFT;
if (fixP->fx_size == 2)
Index: tc-d10v.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gas/config/tc-d10v.h,v
retrieving revision 1.19
diff -d -c -p -3 -r1.19 tc-d10v.h
*** tc-d10v.h 2001/11/25 23:42:22 1.19
--- tc-d10v.h 2001/12/18 15:03:28
***************
*** 34,39 ****
--- 34,41 ----
#define TARGET_FORMAT "elf32-d10v"
+ #define MD_APPLY_FIX3
+
/* Call md_pcrel_from_section, not md_pcrel_from. */
#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC)
long md_pcrel_from_section PARAMS ((fixS *, segT));
Alan Matsuoka
GCC Engineering
Red Hat Canada, Ltd
mailto:alanm@redhat.com Tel: (416) 482-2661 x250 / Fax: (416) 482-6299