/* tc-mips.c -- assemble code for a MIPS chip.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
/* Classifies the kind of instructions we're interested in when
implementing -mfix-vr4120. */
-enum fix_vr4120_class {
+enum fix_vr4120_class
+{
FIX_VR4120_MACC,
FIX_VR4120_DMACC,
FIX_VR4120_MULT,
NUM_FIX_VR4120_CLASSES
};
+/* ...likewise -mfix-loongson2f-jump. */
+static bfd_boolean mips_fix_loongson2f_jump;
+
+/* ...likewise -mfix-loongson2f-nop. */
+static bfd_boolean mips_fix_loongson2f_nop;
+
+/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed. */
+static bfd_boolean mips_fix_loongson2f;
+
/* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
there must be at least one other instruction between an instruction
of type X and an instruction of type Y. */
enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
static void append_insn
- (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
+ (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
static void mips_no_prev_insn (void);
+static void macro_build (expressionS *, const char *, const char *, ...);
static void mips16_macro_build
- (expressionS *, const char *, const char *, va_list);
+ (expressionS *, const char *, const char *, va_list *);
static void load_register (int, expressionS *, int);
static void macro_start (void);
static void macro_end (void);
}
/* Return TRUE if opcode MO is valid on the currently selected ISA and
- architecture. If EXPANSIONP is TRUE then this check is done while
- expanding a macro. Use is_opcode_valid_16 for MIPS16 opcodes. */
+ architecture. Use is_opcode_valid_16 for MIPS16 opcodes. */
static bfd_boolean
-is_opcode_valid (const struct mips_opcode *mo, bfd_boolean expansionp)
+is_opcode_valid (const struct mips_opcode *mo)
{
int isa = mips_opts.isa;
int fp_s, fp_d;
if (mips_opts.ase_smartmips)
isa |= INSN_SMARTMIPS;
- /* For user code we don't check for mips_opts.mips16 since we want
- to allow jalx if -mips16 was specified on the command line. */
- if (expansionp ? mips_opts.mips16 : file_ase_mips16)
- isa |= INSN_MIPS16;
-
/* Don't accept instructions based on the ISA if the CPU does not implement
all the coprocessor insns. */
if (NO_ISA_COP (mips_opts.arch)
if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
{
create_insn (&nop_insn, mips_opcodes + i);
+ if (mips_fix_loongson2f_nop)
+ nop_insn.insn_opcode = LOONGSON2F_NOP_INSN;
nop_insn.fixed_p = 1;
}
}
if (tmp_nops > nops)
nops = tmp_nops;
}
- else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
+ else if (mips_opts.mips16
+ && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
+ | MIPS16_INSN_COND_BRANCH)))
{
tmp_nops = nops_for_sequence (1, hist, insn);
if (tmp_nops > nops)
return nops;
}
+/* Fix NOP issue: Replace nops by "or at,at,zero". */
+
+static void
+fix_loongson2f_nop (struct mips_cl_insn * ip)
+{
+ if (strcmp (ip->insn_mo->name, "nop") == 0)
+ ip->insn_opcode = LOONGSON2F_NOP_INSN;
+}
+
+/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
+ jr target pc &= 'hffff_ffff_cfff_ffff. */
+
+static void
+fix_loongson2f_jump (struct mips_cl_insn * ip)
+{
+ if (strcmp (ip->insn_mo->name, "j") == 0
+ || strcmp (ip->insn_mo->name, "jr") == 0
+ || strcmp (ip->insn_mo->name, "jalr") == 0)
+ {
+ int sreg;
+ expressionS ep;
+
+ if (! mips_opts.at)
+ return;
+
+ sreg = EXTRACT_OPERAND (RS, *ip);
+ if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
+ return;
+
+ ep.X_op = O_constant;
+ ep.X_add_number = 0xcfff0000;
+ macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16);
+ ep.X_add_number = 0xffff;
+ macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16);
+ macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG);
+ }
+}
+
+static void
+fix_loongson2f (struct mips_cl_insn * ip)
+{
+ if (mips_fix_loongson2f_nop)
+ fix_loongson2f_nop (ip);
+
+ if (mips_fix_loongson2f_jump)
+ fix_loongson2f_jump (ip);
+}
+
/* Output an instruction. IP is the instruction information.
ADDRESS_EXPR is an operand of the instruction to be used with
RELOC_TYPE. */
bfd_boolean relaxed_branch = FALSE;
segment_info_type *si = seg_info (now_seg);
+ if (mips_fix_loongson2f)
+ fix_loongson2f (ip);
+
/* Mark instruction labels in mips16 mode. */
mips16_mark_labels ();
if (mips_opts.mips16)
{
- mips16_macro_build (ep, name, fmt, args);
+ mips16_macro_build (ep, name, fmt, &args);
va_end (args);
return;
}
macros will never generate MDMX, MIPS-3D, or MT instructions. */
if (strcmp (fmt, mo->args) == 0
&& mo->pinfo != INSN_MACRO
- && is_opcode_valid (mo, TRUE))
+ && is_opcode_valid (mo))
break;
++mo;
static void
mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
- va_list args)
+ va_list *args)
{
struct mips_opcode *mo;
struct mips_cl_insn insn;
case 'y':
case 'w':
- MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RY, insn, va_arg (*args, int));
continue;
case 'x':
case 'v':
- MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RX, insn, va_arg (*args, int));
continue;
case 'z':
- MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (RZ, insn, va_arg (*args, int));
continue;
case 'Z':
- MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (*args, int));
continue;
case '0':
continue;
case 'X':
- MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (*args, int));
continue;
case 'Y':
{
int regno;
- regno = va_arg (args, int);
+ regno = va_arg (*args, int);
regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
MIPS16_INSERT_OPERAND (REG32R, insn, regno);
}
continue;
case '6':
- MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
+ MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (*args, int));
continue;
}
/* Quiet this warning. */
mips_cprestore_valid = 1;
}
+ if (mips_opts.noreorder)
+ macro_build (NULL, "nop", "");
expr1.X_add_number = mips_cprestore_offset;
macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
mips_gp_register,
gas_assert (strcmp (insn->name, str) == 0);
- ok = is_opcode_valid (insn, FALSE);
+ ok = is_opcode_valid (insn);
if (! ok)
{
if (insn + 1 < &mips_opcodes[NUMOPCODES]
/* Set the argument to the current address in the
section. */
offset_expr.X_op = O_symbol;
- offset_expr.X_add_symbol =
- symbol_new ("L0\001", now_seg,
- (valueT) frag_now_fix (), frag_now);
+ offset_expr.X_add_symbol = symbol_temp_new_now ();
offset_expr.X_add_number = 0;
/* Put the floating point number into the section. */
OPTION_MNO_7000_HILO_FIX,
OPTION_FIX_24K,
OPTION_NO_FIX_24K,
+ OPTION_FIX_LOONGSON2F_JUMP,
+ OPTION_NO_FIX_LOONGSON2F_JUMP,
+ OPTION_FIX_LOONGSON2F_NOP,
+ OPTION_NO_FIX_LOONGSON2F_NOP,
OPTION_FIX_VR4120,
OPTION_NO_FIX_VR4120,
OPTION_FIX_VR4130,
{"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
{"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
{"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
+ {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP},
+ {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP},
+ {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
+ {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
{"mfix-vr4120", no_argument, NULL, OPTION_FIX_VR4120},
{"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
{"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130},
mips_fix_24k = 0;
break;
+ case OPTION_FIX_LOONGSON2F_JUMP:
+ mips_fix_loongson2f_jump = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_JUMP:
+ mips_fix_loongson2f_jump = FALSE;
+ break;
+
+ case OPTION_FIX_LOONGSON2F_NOP:
+ mips_fix_loongson2f_nop = TRUE;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_NOP:
+ mips_fix_loongson2f_nop = FALSE;
+ break;
+
case OPTION_FIX_VR4120:
mips_fix_vr4120 = 1;
break;
return 0;
}
+ mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump;
+
return 1;
}
\f
hi_pos = pos;
if ((*pos)->fx_r_type == looking_for_rtype
- && (*pos)->fx_addsy == l->fixp->fx_addsy
+ && symbol_same_p ((*pos)->fx_addsy, l->fixp->fx_addsy)
&& (*pos)->fx_offset >= l->fixp->fx_offset
&& (lo_pos == NULL
|| (*pos)->fx_offset < (*lo_pos)->fx_offset
section_alignment = get_absolute_expression ();
else
section_alignment = 0;
+ /* FIXME: really ignore? */
+ (void) section_alignment;
section_name = xstrdup (section_name);
mips_handle_align (fragS *fragp)
{
char *p;
+ int bytes, size, excess;
+ valueT opcode;
if (fragp->fr_type != rs_align_code)
return;
p = fragp->fr_literal + fragp->fr_fix;
if (*p)
{
- int bytes;
+ opcode = mips16_nop_insn.insn_opcode;
+ size = 2;
+ }
+ else
+ {
+ opcode = nop_insn.insn_opcode;
+ size = 4;
+ }
- bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
- if (bytes & 1)
- {
- *p++ = 0;
- fragp->fr_fix++;
- }
- md_number_to_chars (p, mips16_nop_insn.insn_opcode, 2);
- fragp->fr_var = 2;
+ bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+ excess = bytes % size;
+ if (excess != 0)
+ {
+ /* If we're not inserting a whole number of instructions,
+ pad the end of the fixed part of the frag with zeros. */
+ memset (p, 0, excess);
+ p += excess;
+ fragp->fr_fix += excess;
}
+
+ md_number_to_chars (p, opcode, size);
+ fragp->fr_var = size;
}
static void
{
segT saved_seg = now_seg;
subsegT saved_subseg = now_subseg;
- valueT dot;
expressionS exp;
char *fragp;
- dot = frag_now_fix ();
-
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
cur_proc_ptr->func_sym = symbolP;
- symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
-
++numprocs;
if (debug_type == DEBUG_STABS)
S_GET_NAME (symbolP));
}
+ symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+
demand_empty_rest_of_line ();
}
-mmt generate MT instructions\n\
-mno-mt do not generate MT instructions\n"));
fprintf (stream, _("\
+-mfix-loongson2f-jump work around Loongson2F JUMP instructions\n\
+-mfix-loongson2f-nop work around Loongson2F NOP errata\n\
-mfix-vr4120 work around certain VR4120 errata\n\
-mfix-vr4130 work around VR4130 mflo/mfhi errata\n\
-mfix-24k insert a nop after ERET and DERET instructions\n\
#endif
}
+#ifdef TE_IRIX
enum dwarf2_format
mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
{
if (HAVE_64BIT_SYMBOLS)
- {
-#ifdef TE_IRIX
- return dwarf2_format_64bit_irix;
-#else
- return dwarf2_format_64bit;
-#endif
- }
+ return dwarf2_format_64bit_irix;
else
return dwarf2_format_32bit;
}
+#endif
int
mips_dwarf2_addr_size (void)