Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Typedefs | Enumerations | Functions | Variables
tc-mips.c File Reference
#include "as.h"
#include "config.h"
#include "subsegs.h"
#include "safe-ctype.h"
#include "opcode/mips.h"
#include "itbl-ops.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
#include "ecoff.h"

Go to the source code of this file.

Classes

struct  mips_cl_insn
struct  mips_set_options
struct  mips_hi_fixup
struct  mips_cpu_info
struct  insn_label_list
struct  regname
struct  mips_immed
struct  mips16_immed_operand
struct  percent_op_match
struct  mips_option_stack
struct  proc

Defines

#define DBG(x)
#define NO_ECOFF_DEBUGGING
#define ECOFF_DEBUGGING   0
#define ZERO   0
#define AT   1
#define TREG   24
#define PIC_CALL_REG   25
#define KT0   26
#define KT1   27
#define GP   28
#define SP   29
#define FP   30
#define RA   31
#define ILLEGAL_REG   (32)
#define ECOFF_LITTLE_FORMAT   "ecoff-littlemips"
#define RDATA_SECTION_NAME
#define ISA_SUPPORTS_MIPS16E
#define ISA_SUPPORTS_SMARTMIPS
#define ISA_SUPPORTS_DSP_ASE
#define ISA_SUPPORTS_DSP64_ASE   (mips_opts.isa == ISA_MIPS64R2)
#define ISA_SUPPORTS_DSPR2_ASE
#define ISA_SUPPORTS_MT_ASE
#define ABI_NEEDS_32BIT_REGS(ABI)   ((ABI) == O32_ABI)
#define ABI_NEEDS_64BIT_REGS(ABI)
#define ISA_HAS_64BIT_REGS(ISA)
#define ISA_HAS_64BIT_FPRS(ISA)
#define ISA_HAS_DROR(ISA)   ((ISA) == ISA_MIPS64R2)
#define ISA_HAS_ROR(ISA)
#define ISA_HAS_ODD_SINGLE_FPR(ISA)
#define ISA_HAS_MXHC1(ISA)
#define HAVE_32BIT_GPRS   (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
#define HAVE_32BIT_FPRS   (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
#define HAVE_64BIT_GPRS   (!HAVE_32BIT_GPRS)
#define HAVE_64BIT_FPRS   (!HAVE_32BIT_FPRS)
#define HAVE_NEWABI   (mips_abi == N32_ABI || mips_abi == N64_ABI)
#define HAVE_64BIT_OBJECTS   (mips_abi == N64_ABI)
#define HAVE_IN_PLACE_ADDENDS   (!HAVE_NEWABI)
#define HAVE_64BIT_ADDRESSES   (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
#define HAVE_32BIT_ADDRESSES   (!HAVE_64BIT_ADDRESSES)
#define HAVE_32BIT_SYMBOLS   (HAVE_32BIT_ADDRESSES || !HAVE_64BIT_OBJECTS || mips_opts.sym32)
#define HAVE_64BIT_SYMBOLS   (!HAVE_32BIT_SYMBOLS)
#define ADDRESS_ADD_INSN   (HAVE_32BIT_ADDRESSES ? "addu" : "daddu")
#define ADDRESS_ADDI_INSN   (HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu")
#define ADDRESS_LOAD_INSN   (HAVE_32BIT_ADDRESSES ? "lw" : "ld")
#define ADDRESS_STORE_INSN   (HAVE_32BIT_ADDRESSES ? "sw" : "sd")
#define CPU_HAS_MIPS16(cpu)
#define CPU_HAS_DROR(CPU)   ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
#define CPU_HAS_ROR(CPU)   CPU_HAS_DROR (CPU)
#define hilo_interlocks
#define gpr_interlocks
#define cop_interlocks
#define cop_mem_interlocks   (mips_opts.isa != ISA_MIPS1)
#define MF_HILO_INSN(PINFO)   ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
#define N_RMASK   0xc4
#define N_VFP   0xd4
#define MAX_VR4130_NOPS   4
#define MAX_DELAY_NOPS   2
#define MAX_NOPS   4
#define NOP_INSN   (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn)
#define X   ILLEGAL_REG
#define RELAX_ENCODE(FIRST, SECOND)   (((FIRST) << 8) | (SECOND))
#define RELAX_FIRST(X)   (((X) >> 8) & 0xff)
#define RELAX_SECOND(X)   ((X) & 0xff)
#define RELAX_USE_SECOND   0x10000
#define RELAX_SECOND_LONGER   0x20000
#define RELAX_NOMACRO   0x40000
#define RELAX_DELAY_SLOT   0x80000
#define RELAX_BRANCH_ENCODE(uncond, likely, link, toofar)
#define RELAX_BRANCH_P(i)   (((i) & 0xf0000000) == 0xc0000000)
#define RELAX_BRANCH_UNCOND(i)   (((i) & 8) != 0)
#define RELAX_BRANCH_LIKELY(i)   (((i) & 4) != 0)
#define RELAX_BRANCH_LINK(i)   (((i) & 2) != 0)
#define RELAX_BRANCH_TOOFAR(i)   (((i) & 1) != 0)
#define RELAX_MIPS16_ENCODE(type, small, ext, dslot, jal_dslot)
#define RELAX_MIPS16_P(i)   (((i) & 0xc0000000) == 0x80000000)
#define RELAX_MIPS16_TYPE(i)   ((i) & 0xff)
#define RELAX_MIPS16_USER_SMALL(i)   (((i) & 0x100) != 0)
#define RELAX_MIPS16_USER_EXT(i)   (((i) & 0x200) != 0)
#define RELAX_MIPS16_DSLOT(i)   (((i) & 0x400) != 0)
#define RELAX_MIPS16_JAL_DSLOT(i)   (((i) & 0x800) != 0)
#define RELAX_MIPS16_EXTENDED(i)   (((i) & 0x1000) != 0)
#define RELAX_MIPS16_MARK_EXTENDED(i)   ((i) | 0x1000)
#define RELAX_MIPS16_CLEAR_EXTENDED(i)   ((i) &~ 0x1000)
#define RELAX_MIPS16_LONG_BRANCH(i)   (((i) & 0x2000) != 0)
#define RELAX_MIPS16_MARK_LONG_BRANCH(i)   ((i) | 0x2000)
#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i)   ((i) &~ 0x2000)
#define IS_SEXT_32BIT_NUM(x)
#define IS_SEXT_16BIT_NUM(x)
#define IS_ZEXT_32BIT_NUM(x)
#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT)
#define EXTRACT_BITS(STRUCT, MASK, SHIFT)   (((STRUCT) >> (SHIFT)) & (MASK))
#define INSERT_OPERAND(FIELD, INSN, VALUE)   INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD)
#define MIPS16_INSERT_OPERAND(FIELD, INSN, VALUE)
#define EXTRACT_OPERAND(FIELD, INSN)   EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD)
#define MIPS16_EXTRACT_OPERAND(FIELD, INSN)
#define internalError()   as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
#define MIPS_CPU_IS_ISA   0x0001 /* Is this an ISA? (If 0, a CPU.) */
#define MIPS_CPU_ASE_SMARTMIPS   0x0002 /* CPU implements SmartMIPS ASE */
#define MIPS_CPU_ASE_DSP   0x0004 /* CPU implements DSP ASE */
#define MIPS_CPU_ASE_MT   0x0008 /* CPU implements MT ASE */
#define MIPS_CPU_ASE_MIPS3D   0x0010 /* CPU implements MIPS-3D ASE */
#define MIPS_CPU_ASE_MDMX   0x0020 /* CPU implements MDMX ASE */
#define MIPS_CPU_ASE_DSPR2   0x0040 /* CPU implements DSP R2 ASE */
#define label_list   tc_segment_info_data
#define CONFLICT(FIRST, SECOND)   vr4120_conflicts[FIX_VR4120_##FIRST] |= 1 << FIX_VR4120_##SECOND
#define RTYPE_MASK   0x1ff00
#define RTYPE_NUM   0x00100
#define RTYPE_FPU   0x00200
#define RTYPE_FCC   0x00400
#define RTYPE_VEC   0x00800
#define RTYPE_GP   0x01000
#define RTYPE_CP0   0x02000
#define RTYPE_PC   0x04000
#define RTYPE_ACC   0x08000
#define RTYPE_CCC   0x10000
#define RNUM_MASK   0x000ff
#define RWARN   0x80000
#define GENERIC_REGISTER_NUMBERS
#define FPU_REGISTER_NAMES
#define FPU_CONDITION_CODE_NAMES
#define COPROC_CONDITION_CODE_NAMES
#define N32N64_SYMBOLIC_REGISTER_NAMES
#define O32_SYMBOLIC_REGISTER_NAMES
#define SYMBOLIC_REGISTER_NAMES
#define MIPS16_SPECIAL_REGISTER_NAMES   {"$pc", RTYPE_PC | 0}
#define MDMX_VECTOR_REGISTER_NAMES
#define MIPS_DSP_ACCUMULATOR_NAMES
#define INSN2_USES_REG(REG, CLASS)   (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
#define COUNT_TOP_ZEROES(v)
#define USE_BITS(mask, shift)   (used_bits |= ((mask) << (shift)))
#define SKIP_SPACE_TABS(S)   { while (*(S) == ' ' || *(S) == '\t') ++(S); }
#define MIPS16_NUM_IMMED   (sizeof mips16_immed_operands / sizeof mips16_immed_operands[0])
#define OPTION_ARCH_BASE   (OPTION_MD_BASE)
#define OPTION_MARCH   (OPTION_ARCH_BASE + 0)
#define OPTION_MTUNE   (OPTION_ARCH_BASE + 1)
#define OPTION_MIPS1   (OPTION_ARCH_BASE + 2)
#define OPTION_MIPS2   (OPTION_ARCH_BASE + 3)
#define OPTION_MIPS3   (OPTION_ARCH_BASE + 4)
#define OPTION_MIPS4   (OPTION_ARCH_BASE + 5)
#define OPTION_MIPS5   (OPTION_ARCH_BASE + 6)
#define OPTION_MIPS32   (OPTION_ARCH_BASE + 7)
#define OPTION_MIPS64   (OPTION_ARCH_BASE + 8)
#define OPTION_MIPS32R2   (OPTION_ARCH_BASE + 9)
#define OPTION_MIPS64R2   (OPTION_ARCH_BASE + 10)
#define OPTION_ASE_BASE   (OPTION_ARCH_BASE + 11)
#define OPTION_MIPS16   (OPTION_ASE_BASE + 0)
#define OPTION_NO_MIPS16   (OPTION_ASE_BASE + 1)
#define OPTION_MIPS3D   (OPTION_ASE_BASE + 2)
#define OPTION_NO_MIPS3D   (OPTION_ASE_BASE + 3)
#define OPTION_MDMX   (OPTION_ASE_BASE + 4)
#define OPTION_NO_MDMX   (OPTION_ASE_BASE + 5)
#define OPTION_DSP   (OPTION_ASE_BASE + 6)
#define OPTION_NO_DSP   (OPTION_ASE_BASE + 7)
#define OPTION_MT   (OPTION_ASE_BASE + 8)
#define OPTION_NO_MT   (OPTION_ASE_BASE + 9)
#define OPTION_SMARTMIPS   (OPTION_ASE_BASE + 10)
#define OPTION_NO_SMARTMIPS   (OPTION_ASE_BASE + 11)
#define OPTION_DSPR2   (OPTION_ASE_BASE + 12)
#define OPTION_NO_DSPR2   (OPTION_ASE_BASE + 13)
#define OPTION_COMPAT_ARCH_BASE   (OPTION_ASE_BASE + 14)
#define OPTION_M4650   (OPTION_COMPAT_ARCH_BASE + 0)
#define OPTION_NO_M4650   (OPTION_COMPAT_ARCH_BASE + 1)
#define OPTION_M4010   (OPTION_COMPAT_ARCH_BASE + 2)
#define OPTION_NO_M4010   (OPTION_COMPAT_ARCH_BASE + 3)
#define OPTION_M4100   (OPTION_COMPAT_ARCH_BASE + 4)
#define OPTION_NO_M4100   (OPTION_COMPAT_ARCH_BASE + 5)
#define OPTION_M3900   (OPTION_COMPAT_ARCH_BASE + 6)
#define OPTION_NO_M3900   (OPTION_COMPAT_ARCH_BASE + 7)
#define OPTION_FIX_BASE   (OPTION_COMPAT_ARCH_BASE + 8)
#define OPTION_M7000_HILO_FIX   (OPTION_FIX_BASE + 0)
#define OPTION_MNO_7000_HILO_FIX   (OPTION_FIX_BASE + 1)
#define OPTION_FIX_VR4120   (OPTION_FIX_BASE + 2)
#define OPTION_NO_FIX_VR4120   (OPTION_FIX_BASE + 3)
#define OPTION_FIX_VR4130   (OPTION_FIX_BASE + 4)
#define OPTION_NO_FIX_VR4130   (OPTION_FIX_BASE + 5)
#define OPTION_MISC_BASE   (OPTION_FIX_BASE + 6)
#define OPTION_TRAP   (OPTION_MISC_BASE + 0)
#define OPTION_BREAK   (OPTION_MISC_BASE + 1)
#define OPTION_EB   (OPTION_MISC_BASE + 2)
#define OPTION_EL   (OPTION_MISC_BASE + 3)
#define OPTION_FP32   (OPTION_MISC_BASE + 4)
#define OPTION_GP32   (OPTION_MISC_BASE + 5)
#define OPTION_CONSTRUCT_FLOATS   (OPTION_MISC_BASE + 6)
#define OPTION_NO_CONSTRUCT_FLOATS   (OPTION_MISC_BASE + 7)
#define OPTION_FP64   (OPTION_MISC_BASE + 8)
#define OPTION_GP64   (OPTION_MISC_BASE + 9)
#define OPTION_RELAX_BRANCH   (OPTION_MISC_BASE + 10)
#define OPTION_NO_RELAX_BRANCH   (OPTION_MISC_BASE + 11)
#define OPTION_MSHARED   (OPTION_MISC_BASE + 12)
#define OPTION_MNO_SHARED   (OPTION_MISC_BASE + 13)
#define OPTION_MSYM32   (OPTION_MISC_BASE + 14)
#define OPTION_MNO_SYM32   (OPTION_MISC_BASE + 15)

Typedefs

typedef struct proc procS

Enumerations

enum  mips_abi_level {
  NO_ABI = 0, O32_ABI, O64_ABI, N32_ABI,
  N64_ABI, EABI_ABI
}
enum  fix_vr4120_class {
  FIX_VR4120_MACC, FIX_VR4120_DMACC, FIX_VR4120_MULT, FIX_VR4120_DMULT,
  FIX_VR4120_DIV, FIX_VR4120_MTHILO, NUM_FIX_VR4120_CLASSES
}
enum  mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG }

Functions

static int nopic_need_relax (symbolS *, int)
static void append_insn (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r)
static void mips_no_prev_insn (void)
static void mips16_macro_build (expressionS *, const char *, const char *, va_list)
static void load_register (int, expressionS *, int)
static void macro_start (void)
static void macro_end (void)
static void macro (struct mips_cl_insn *ip)
static void mips16_macro (struct mips_cl_insn *ip)
static void mips_ip (char *str, struct mips_cl_insn *ip)
static void mips16_ip (char *str, struct mips_cl_insn *ip)
static void mips16_immed (char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean, bfd_boolean, unsigned long *, bfd_boolean *, unsigned short *)
static size_t my_getSmallExpression (expressionS *, bfd_reloc_code_real_type *, char *)
static void my_getExpression (expressionS *, char *)
static void s_align (int)
static void s_change_sec (int)
static void s_change_section (int)
static void s_cons (int)
static void s_float_cons (int)
static void s_mips_globl (int)
static void s_option (int)
static void s_mipsset (int)
static void s_abicalls (int)
static void s_cpload (int)
static void s_cpsetup (int)
static void s_cplocal (int)
static void s_cprestore (int)
static void s_cpreturn (int)
static void s_gpvalue (int)
static void s_gpword (int)
static void s_gpdword (int)
static void s_cpadd (int)
static void s_insn (int)
static void md_obj_begin (void)
static void md_obj_end (void)
static void s_mips_ent (int)
static void s_mips_end (int)
static void s_mips_frame (int)
static void s_mips_mask (int reg_type)
static void s_mips_stab (int)
static void s_mips_weakext (int)
static void s_mips_file (int)
static void s_mips_loc (int)
static bfd_boolean pic_need_relax (symbolS *, asection *)
static int relaxed_branch_length (fragS *, asection *, int)
static int validate_mips_insn (const struct mips_opcode *)
static struct mips_cpu_infomips_parse_cpu (const char *, const char *)
static struct mips_cpu_infomips_cpu_info_from_isa (int)
static struct mips_cpu_infomips_cpu_info_from_arch (int)
void pop_insert (const pseudo_typeS *)
void mips_pop_insert (void)
static void mips_clear_insn_labels (void)
const char * mips_target_format (void)
static unsigned int insn_length (const struct mips_cl_insn *insn)
static void create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
static void install_insn (const struct mips_cl_insn *insn)
static void move_insn (struct mips_cl_insn *insn, fragS *frag, long where)
static void add_fixed_insn (struct mips_cl_insn *insn)
static void add_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var, relax_substateT subtype, symbolS *symbol, offsetT offset)
static void insert_into_history (unsigned int first, unsigned int n, const struct mips_cl_insn *insn)
static void emit_nop (void)
static void init_vr4120_conflicts (void)
static int reg_lookup (char **s, unsigned int types, unsigned int *regnop)
void md_begin (void)
void md_mips_end (void)
void md_assemble (char *str)
static bfd_boolean reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
static bfd_boolean fixup_has_matching_lo_p (fixS *fixp)
static int insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg, enum mips_regclass class)
static int reg_needs_delay (unsigned int reg)
static void mips_move_labels (void)
static bfd_boolean s_is_linkonce (symbolS *sym, segT from_seg)
static void mips16_mark_labels (void)
static void relax_close_frag (void)
static void relax_start (symbolS *symbol)
static void relax_switch (void)
static void relax_end (void)
static unsigned int classify_vr4120_insn (const char *name)
static unsigned int insns_between (const struct mips_cl_insn *insn1, const struct mips_cl_insn *insn2)
static int nops_for_vr4130 (const struct mips_cl_insn *history, const struct mips_cl_insn *insn)
static int nops_for_insn (const struct mips_cl_insn *history, const struct mips_cl_insn *insn)
static int nops_for_sequence (int num_insns, const struct mips_cl_insn *history,...)
static int nops_for_insn_or_target (const struct mips_cl_insn *history, const struct mips_cl_insn *insn)
void mips_emit_delays (void)
static void start_noreorder (void)
static void end_noreorder (void)
static const char * macro_warning (relax_substateT subtype)
static void macro_read_relocs (va_list *args, bfd_reloc_code_real_type *r)
static void macro_build (expressionS *ep, const char *name, const char *fmt,...)
static void normalize_constant_expr (expressionS *ex)
static void normalize_address_expr (expressionS *ex)
static void macro_build_jalr (expressionS *ep)
static void macro_build_lui (expressionS *ep, int regnum)
static void macro_build_ldst_constoffset (expressionS *ep, const char *op, int treg, int breg, int dbl)
static void set_at (int reg, int unsignedp)
static void check_absolute_expr (struct mips_cl_insn *ip, expressionS *ex)
static void load_delay_nop (void)
static void load_address (int reg, expressionS *ep, int *used_at)
static void move_register (int dest, int source)
static void load_got_offset (int dest, expressionS *local)
static void add_got_offset (int dest, expressionS *local)
static void add_got_offset_hilo (int dest, expressionS *local, int tmp)
static int mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum)
static bfd_boolean parse_relocation (char **str, bfd_reloc_code_real_type *reloc)
char * md_atof (int type, char *litP, int *sizeP)
void md_number_to_chars (char *buf, valueT val, int n)
static void mips_set_option_string (const char **string_ptr, const char *new_value)
int md_parse_option (int c, char *arg)
static void mips_set_architecture (const struct mips_cpu_info *info)
static void mips_set_tune (const struct mips_cpu_info *info)
void mips_after_parse_args (void)
void mips_init_after_args (void)
long md_pcrel_from (fixS *fixP)
void mips_frob_file_before_adjust (void)
void mips_frob_file (void)
int mips_force_relocation (fixS *fixp)
void md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
static symbolS * get_symbol (void)
static void mips_align (int to, int fill, symbolS *label)
static void s_align (int x ATTRIBUTE_UNUSED)
void s_change_section (int ignore ATTRIBUTE_UNUSED)
void mips_enable_auto_align (void)
static void s_mips_globl (int x ATTRIBUTE_UNUSED)
static void s_option (int x ATTRIBUTE_UNUSED)
static void s_mipsset (int x ATTRIBUTE_UNUSED)
static void s_abicalls (int ignore ATTRIBUTE_UNUSED)
static void s_cpload (int ignore ATTRIBUTE_UNUSED)
static void s_cpsetup (int ignore ATTRIBUTE_UNUSED)
static void s_cplocal (int ignore ATTRIBUTE_UNUSED)
static void s_cprestore (int ignore ATTRIBUTE_UNUSED)
static void s_cpreturn (int ignore ATTRIBUTE_UNUSED)
static void s_gpvalue (int ignore ATTRIBUTE_UNUSED)
static void s_gpword (int ignore ATTRIBUTE_UNUSED)
static void s_gpdword (int ignore ATTRIBUTE_UNUSED)
static void s_cpadd (int ignore ATTRIBUTE_UNUSED)
static void s_insn (int ignore ATTRIBUTE_UNUSED)
static void s_mips_weakext (int ignore ATTRIBUTE_UNUSED)
int tc_get_register (int frame)
valueT md_section_align (asection *seg, valueT addr)
static int mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
int md_estimate_size_before_relax (fragS *fragp, asection *segtype)
int mips_fix_adjustable (fixS *fixp)
arelent ** tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
int mips_relax_frag (asection *sec, fragS *fragp, long stretch)
void md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
void mips_define_label (symbolS *sym)
void mips_handle_align (fragS *fragp)
static long get_number (void)
static void s_mips_file (int x ATTRIBUTE_UNUSED)
static void s_mips_loc (int x ATTRIBUTE_UNUSED)
static void s_mips_end (int x ATTRIBUTE_UNUSED)
static void s_mips_frame (int ignore ATTRIBUTE_UNUSED)
static bfd_boolean mips_strict_matching_cpu_name_p (const char *canonical, const char *given)
static bfd_boolean mips_matching_cpu_name_p (const char *canonical, const char *given)
static void show (FILE *stream, const char *string, int *col_p, int *first_p)
void md_show_usage (FILE *stream)
enum dwarf2_format mips_dwarf2_format (void)
int mips_dwarf2_addr_size (void)
void mips_cfi_frame_initial_instructions (void)
int tc_mips_regname_to_dw2regnum (char *regname)

Variables

int mips_flag_mdebug = -1
int mips_flag_pdr = TRUE
int target_big_endian
static int file_mips_gp32 = -1
static int file_mips_fp32 = -1
static struct mips_set_options
unsigned long mips_gprmask
unsigned long mips_cprmask [4]
static int file_mips_isa = ISA_UNKNOWN
static int file_ase_mips16
static int file_ase_mips3d
static int file_ase_mdmx
static int file_ase_smartmips
static int file_ase_dsp
static int file_ase_dspr2
static int file_ase_mt
static int file_mips_arch = CPU_UNKNOWN
static const char * mips_arch_string
static int mips_tune = CPU_UNKNOWN
static const char * mips_tune_string
static int mips_32bitmode = 0
static struct hash_controlop_hash = NULL
static struct hash_controlmips16_op_hash = NULL
const char comment_chars [] = "#"
const char line_comment_chars [] = "#"
const char line_separator_chars [] = ";"
const char EXP_CHARS [] = "eE"
const char FLT_CHARS [] = "rRsSfFdDxXpP"
static char * insn_error
static int auto_align = 1
static offsetT mips_cprestore_offset = -1
static offsetT mips_cpreturn_offset = -1
static int mips_cpreturn_register = -1
static int mips_gp_register = GP
static int mips_gprel_offset = 0
static int mips_cprestore_valid = 0
static int mips_frame_reg = SP
static int mips_frame_reg_valid = 0
static int mips_optimize = 2
static int mips_debug = 0
static struct mips_cl_insn [1+MAX_NOPS]
static fragS * prev_nop_frag
static int prev_nop_frag_holds
static int prev_nop_frag_required
static int prev_nop_frag_since
static struct mips_hi_fixupmips_hi_fixup_list
static fragS * prev_reloc_op_frag
static const int mips32_to_16_reg_map []
static const unsigned int mips16_to_32_reg_map []
static unsigned int vr4120_conflicts [NUM_FIX_VR4120_CLASSES]
static int mips_fix_vr4120
static int mips_fix_vr4130
static int mips_relax_branch
struct {
int sequence
fixS * first_fixup
unsigned int sizes [2]
symbolS * symbol
mips_relax
struct {
bfd_boolean delay_slot_p
unsigned int sizes [2]
fragS * first_frag
mips_macro_warning
static const pseudo_typeS mips_pseudo_table []
static const pseudo_typeS mips_nonecoff_pseudo_table []
static struct insn_label_listfree_insn_labels
static char * expr_end
static expressionS imm_expr
static expressionS imm2_expr
static expressionS offset_expr
static bfd_reloc_code_real_type imm_reloc [3] = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}
static bfd_reloc_code_real_type offset_reloc [3] = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}
static bfd_boolean mips16_small
static bfd_boolean mips16_ext
static struct regname []
static struct mips_immed []
static struct mips16_immed_operand []
static struct percent_op_match []
const char * md_shortopts = "O::g::G:"
size_t md_longopts_size = sizeof (md_longopts)
static struct mips_option_stackmips_opts_stack
static procS cur_proc
static procScur_proc_ptr
static int numprocs
static struct mips_cpu_info []

Class Documentation

struct mips_cl_insn

Definition at line 123 of file tc-mips.c.

Collaboration diagram for mips_cl_insn:
Class Members
unsigned short extend
unsigned int fixed_p: 1
fixS * fixp
struct frag * frag
struct mips_opcode * insn_mo
unsigned long insn_opcode
unsigned int mips16_absolute_jump_p: 1
unsigned int noreorder_p: 1
bfd_boolean use_extend
long where
struct mips_set_options

Definition at line 183 of file tc-mips.c.

Class Members
int arch
int ase_dsp
int ase_dspr2
int ase_mdmx
int ase_mips3d
int ase_mt
int ase_smartmips
int fp32
int gp32
int isa
int mips16
int noat
int noautoextend
int nobopt
int nomove
int noreorder
bfd_boolean sym32
int warn_about_macros
struct mips_hi_fixup

Definition at line 659 of file tc-mips.c.

Collaboration diagram for mips_hi_fixup:
Class Members
fixS * fixp
struct mips_hi_fixup * next
segT seg
struct mips_cpu_info

Definition at line 1049 of file tc-mips.c.

Class Members
int cpu
int flags
int isa
const char * name
struct insn_label_list

Definition at line 1173 of file tc-mips.c.

Collaboration diagram for insn_label_list:
Class Members
symbolS * label
struct insn_label_list * next
struct regname

Definition at line 1443 of file tc-mips.c.

Class Members
const char * name
unsigned int num
struct mips_immed

Definition at line 8294 of file tc-mips.c.

Class Members
const char * desc
unsigned long mask
unsigned int shift
char type
struct mips16_immed_operand

Definition at line 10401 of file tc-mips.c.

Class Members
int extbits
int extu
int nbits
int op_shift
int pcrel
int shift
int type
int unsp
struct percent_op_match

Definition at line 10564 of file tc-mips.c.

Class Members
bfd_reloc_code_real_type reloc
const char * str
struct mips_option_stack

Definition at line 12365 of file tc-mips.c.

Collaboration diagram for mips_option_stack:
Class Members
struct mips_option_stack * next
struct proc

Definition at line 72 of file tc-iq2000.c.

Class Members
unsigned long fpreg_mask
unsigned long fpreg_offset
unsigned long frame_offset
unsigned long frame_reg
symbolS * func_end_sym
symbolS * func_sym
symbolS * isym
unsigned long leaf
unsigned long pc_reg
unsigned long reg_mask
unsigned long reg_offset

Define Documentation

#define ABI_NEEDS_32BIT_REGS (   ABI)    ((ABI) == O32_ABI)

Definition at line 320 of file tc-mips.c.

#define ABI_NEEDS_64BIT_REGS (   ABI)
Value:
((ABI) == N32_ABI                  \
   || (ABI) == N64_ABI                    \
   || (ABI) == O64_ABI)

Definition at line 323 of file tc-mips.c.

#define ADDRESS_ADD_INSN   (HAVE_32BIT_ADDRESSES ? "addu" : "daddu")

Definition at line 400 of file tc-mips.c.

#define ADDRESS_ADDI_INSN   (HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu")

Definition at line 403 of file tc-mips.c.

#define ADDRESS_LOAD_INSN   (HAVE_32BIT_ADDRESSES ? "lw" : "ld")

Definition at line 406 of file tc-mips.c.

#define ADDRESS_STORE_INSN   (HAVE_32BIT_ADDRESSES ? "sw" : "sd")

Definition at line 409 of file tc-mips.c.

#define AT   1

Definition at line 92 of file tc-mips.c.

#define CONFLICT (   FIRST,
  SECOND 
)    vr4120_conflicts[FIX_VR4120_##FIRST] |= 1 << FIX_VR4120_##SECOND
#define cop_interlocks
Value:
((mips_opts.isa != ISA_MIPS1                        \
    && mips_opts.isa != ISA_MIPS2                     \
    && mips_opts.isa != ISA_MIPS3)                    \
   || mips_opts.arch == CPU_R4300                     \
   )

Definition at line 464 of file tc-mips.c.

#define cop_mem_interlocks   (mips_opts.isa != ISA_MIPS1)

Definition at line 476 of file tc-mips.c.

Value:
{"$cc0",      RTYPE_FCC | RTYPE_CCC | 0}, \
    {"$cc1",  RTYPE_FCC | RTYPE_CCC | 1}, \
    {"$cc2",  RTYPE_FCC | RTYPE_CCC | 2}, \
    {"$cc3",  RTYPE_FCC | RTYPE_CCC | 3}, \
    {"$cc4",  RTYPE_FCC | RTYPE_CCC | 4}, \
    {"$cc5",  RTYPE_FCC | RTYPE_CCC | 5}, \
    {"$cc6",  RTYPE_FCC | RTYPE_CCC | 6}, \
    {"$cc7",  RTYPE_FCC | RTYPE_CCC | 7}

Definition at line 1539 of file tc-mips.c.

#define COUNT_TOP_ZEROES (   v)

Definition at line 3857 of file tc-mips.c.

#define CPU_HAS_DROR (   CPU)    ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)

Definition at line 418 of file tc-mips.c.

#define CPU_HAS_MIPS16 (   cpu)
Value:
(strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0           \
    || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)

Definition at line 413 of file tc-mips.c.

#define CPU_HAS_ROR (   CPU)    CPU_HAS_DROR (CPU)

Definition at line 421 of file tc-mips.c.

#define DBG (   x)

Definition at line 39 of file tc-mips.c.

#define ECOFF_DEBUGGING   0

Definition at line 71 of file tc-mips.c.

#define ECOFF_LITTLE_FORMAT   "ecoff-littlemips"

Definition at line 107 of file tc-mips.c.

#define EXTRACT_BITS (   STRUCT,
  MASK,
  SHIFT 
)    (((STRUCT) >> (SHIFT)) & (MASK))

Definition at line 926 of file tc-mips.c.

#define EXTRACT_OPERAND (   FIELD,
  INSN 
)    EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD)

Definition at line 942 of file tc-mips.c.

IC IMR SC FP   30

Definition at line 99 of file tc-mips.c.

Value:
{"$fcc0",     RTYPE_FCC | 0},  \
    {"$fcc1", RTYPE_FCC | 1},  \
    {"$fcc2", RTYPE_FCC | 2},  \
    {"$fcc3", RTYPE_FCC | 3},  \
    {"$fcc4", RTYPE_FCC | 4},  \
    {"$fcc5", RTYPE_FCC | 5},  \
    {"$fcc6", RTYPE_FCC | 6},  \
    {"$fcc7", RTYPE_FCC | 7}

Definition at line 1529 of file tc-mips.c.

Definition at line 1495 of file tc-mips.c.

Definition at line 1461 of file tc-mips.c.

#define GP   28

Definition at line 97 of file tc-mips.c.

#define gpr_interlocks
Value:
(mips_opts.isa != ISA_MIPS1  \
   || mips_opts.arch == CPU_R3900)

Definition at line 452 of file tc-mips.c.

Definition at line 389 of file tc-mips.c.

#define HAVE_32BIT_FPRS   (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))

Definition at line 373 of file tc-mips.c.

#define HAVE_32BIT_GPRS   (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))

Definition at line 370 of file tc-mips.c.

#define HAVE_32BIT_SYMBOLS   (HAVE_32BIT_ADDRESSES || !HAVE_64BIT_OBJECTS || mips_opts.sym32)

Definition at line 393 of file tc-mips.c.

#define HAVE_64BIT_ADDRESSES   (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI))

Definition at line 387 of file tc-mips.c.

Definition at line 377 of file tc-mips.c.

Definition at line 376 of file tc-mips.c.

#define HAVE_64BIT_OBJECTS   (mips_abi == N64_ABI)

Definition at line 381 of file tc-mips.c.

Definition at line 395 of file tc-mips.c.

Definition at line 384 of file tc-mips.c.

#define HAVE_NEWABI   (mips_abi == N32_ABI || mips_abi == N64_ABI)

Definition at line 379 of file tc-mips.c.

#define hilo_interlocks
Value:
(mips_opts.isa == ISA_MIPS32                        \
   || mips_opts.isa == ISA_MIPS32R2                   \
   || mips_opts.isa == ISA_MIPS64                     \
   || mips_opts.isa == ISA_MIPS64R2                   \
   || mips_opts.arch == CPU_R4010                     \
   || mips_opts.arch == CPU_R10000                    \
   || mips_opts.arch == CPU_R12000                    \
   || mips_opts.arch == CPU_RM7000                    \
   || mips_opts.arch == CPU_VR5500                    \
   )

Definition at line 435 of file tc-mips.c.

#define ILLEGAL_REG   (32)

Definition at line 102 of file tc-mips.c.

#define INSERT_BITS (   STRUCT,
  VALUE,
  MASK,
  SHIFT 
)
Value:
(STRUCT) = (((STRUCT) & ~((MASK) << (SHIFT))) \
             | (((VALUE) & (MASK)) << (SHIFT)))

Definition at line 920 of file tc-mips.c.

#define INSERT_OPERAND (   FIELD,
  INSN,
  VALUE 
)    INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD)

Definition at line 935 of file tc-mips.c.

#define INSN2_USES_REG (   REG,
  CLASS 
)    (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
#define internalError ( )    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)

Definition at line 987 of file tc-mips.c.

#define IS_SEXT_16BIT_NUM (   x)
Value:
(((x) &~ (offsetT) 0x7fff) == 0                                \
   || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))

Definition at line 909 of file tc-mips.c.

#define IS_SEXT_32BIT_NUM (   x)
Value:
(((x) &~ (offsetT) 0x7fffffff) == 0                                   \
   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))

Definition at line 904 of file tc-mips.c.

#define IS_ZEXT_32BIT_NUM (   x)
Value:
(((x) &~ (offsetT) 0xffffffff) == 0                                   \
   || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))

Definition at line 914 of file tc-mips.c.

#define ISA_HAS_64BIT_FPRS (   ISA)
Value:
((ISA) == ISA_MIPS3                \
   || (ISA) == ISA_MIPS4           \
   || (ISA) == ISA_MIPS5           \
   || (ISA) == ISA_MIPS32R2        \
   || (ISA) == ISA_MIPS64          \
   || (ISA) == ISA_MIPS64R2)

Definition at line 337 of file tc-mips.c.

#define ISA_HAS_64BIT_REGS (   ISA)
Value:
((ISA) == ISA_MIPS3                \
   || (ISA) == ISA_MIPS4           \
   || (ISA) == ISA_MIPS5           \
   || (ISA) == ISA_MIPS64          \
   || (ISA) == ISA_MIPS64R2)

Definition at line 329 of file tc-mips.c.

#define ISA_HAS_DROR (   ISA)    ((ISA) == ISA_MIPS64R2)

Definition at line 347 of file tc-mips.c.

#define ISA_HAS_MXHC1 (   ISA)
Value:
((ISA) == ISA_MIPS32R2             \
   || (ISA) == ISA_MIPS64R2)

Definition at line 366 of file tc-mips.c.

#define ISA_HAS_ODD_SINGLE_FPR (   ISA)
Value:
((ISA) == ISA_MIPS32               \
   || (ISA) == ISA_MIPS32R2        \
   || (ISA) == ISA_MIPS64          \
   || (ISA) == ISA_MIPS64R2)

Definition at line 358 of file tc-mips.c.

#define ISA_HAS_ROR (   ISA)
Value:
((ISA) == ISA_MIPS32R2             \
   || (ISA) == ISA_MIPS64R2        \
   || mips_opts.ase_smartmips)

Definition at line 352 of file tc-mips.c.

#define ISA_SUPPORTS_DSP64_ASE   (mips_opts.isa == ISA_MIPS64R2)

Definition at line 291 of file tc-mips.c.

Value:
(mips_opts.isa == ISA_MIPS32R2            \
                           || mips_opts.isa == ISA_MIPS64R2)

Definition at line 288 of file tc-mips.c.

Value:
(mips_opts.isa == ISA_MIPS32R2            \
                             || mips_opts.isa == ISA_MIPS64R2)

Definition at line 297 of file tc-mips.c.

Value:
(mips_opts.isa == ISA_MIPS32              \
                           || mips_opts.isa == ISA_MIPS32R2           \
                           || mips_opts.isa == ISA_MIPS64             \
                           || mips_opts.isa == ISA_MIPS64R2)

Definition at line 264 of file tc-mips.c.

Value:
(mips_opts.isa == ISA_MIPS32R2            \
                          || mips_opts.isa == ISA_MIPS64R2)

Definition at line 304 of file tc-mips.c.

Value:
(mips_opts.isa == ISA_MIPS32              \
                            || mips_opts.isa == ISA_MIPS32R2)

Definition at line 281 of file tc-mips.c.

#define KT0   26

Definition at line 95 of file tc-mips.c.

#define KT1   27

Definition at line 96 of file tc-mips.c.

#define label_list   tc_segment_info_data

Definition at line 1180 of file tc-mips.c.

#define MAX_DELAY_NOPS   2

Definition at line 614 of file tc-mips.c.

#define MAX_NOPS   4

Definition at line 617 of file tc-mips.c.

#define MAX_VR4130_NOPS   4

Definition at line 611 of file tc-mips.c.

Definition at line 1611 of file tc-mips.c.

#define MF_HILO_INSN (   PINFO)    ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))

Definition at line 479 of file tc-mips.c.

#define MIPS16_EXTRACT_OPERAND (   FIELD,
  INSN 
)
Value:
EXTRACT_BITS ((INSN).insn_opcode, \
              MIPS16OP_MASK_##FIELD, \
              MIPS16OP_SH_##FIELD)

Definition at line 944 of file tc-mips.c.

#define MIPS16_INSERT_OPERAND (   FIELD,
  INSN,
  VALUE 
)
Value:
INSERT_BITS ((INSN).insn_opcode, VALUE, \
              MIPS16OP_MASK_##FIELD, MIPS16OP_SH_##FIELD)

Definition at line 937 of file tc-mips.c.

#define MIPS16_NUM_IMMED   (sizeof mips16_immed_operands / sizeof mips16_immed_operands[0])

Definition at line 10450 of file tc-mips.c.

#define MIPS16_SPECIAL_REGISTER_NAMES   {"$pc", RTYPE_PC | 0}

Definition at line 1608 of file tc-mips.c.

#define MIPS_CPU_ASE_DSP   0x0004 /* CPU implements DSP ASE */

Definition at line 1059 of file tc-mips.c.

#define MIPS_CPU_ASE_DSPR2   0x0040 /* CPU implements DSP R2 ASE */

Definition at line 1063 of file tc-mips.c.

#define MIPS_CPU_ASE_MDMX   0x0020 /* CPU implements MDMX ASE */

Definition at line 1062 of file tc-mips.c.

#define MIPS_CPU_ASE_MIPS3D   0x0010 /* CPU implements MIPS-3D ASE */

Definition at line 1061 of file tc-mips.c.

#define MIPS_CPU_ASE_MT   0x0008 /* CPU implements MT ASE */

Definition at line 1060 of file tc-mips.c.

#define MIPS_CPU_ASE_SMARTMIPS   0x0002 /* CPU implements SmartMIPS ASE */

Definition at line 1058 of file tc-mips.c.

#define MIPS_CPU_IS_ISA   0x0001 /* Is this an ISA? (If 0, a CPU.) */

Definition at line 1057 of file tc-mips.c.

Value:
{"$ac0",      RTYPE_ACC | 0}, \
    {"$ac1",  RTYPE_ACC | 1}, \
    {"$ac2",  RTYPE_ACC | 2}, \
    {"$ac3",  RTYPE_ACC | 3}

Definition at line 1645 of file tc-mips.c.

Value:
{"$a4",       RTYPE_GP | 8},  \
    {"$a5",   RTYPE_GP | 9},  \
    {"$a6",   RTYPE_GP | 10}, \
    {"$a7",   RTYPE_GP | 11}, \
    {"$ta0",  RTYPE_GP | 8},  /* alias for $a4 */ \
    {"$ta1",  RTYPE_GP | 9},  /* alias for $a5 */ \
    {"$ta2",  RTYPE_GP | 10}, /* alias for $a6 */ \
    {"$ta3",  RTYPE_GP | 11}, /* alias for $a7 */ \
    {"$t0",   RTYPE_GP | 12}, \
    {"$t1",   RTYPE_GP | 13}, \
    {"$t2",   RTYPE_GP | 14}, \
    {"$t3",   RTYPE_GP | 15}

Definition at line 1549 of file tc-mips.c.

#define N_RMASK   0xc4

Definition at line 515 of file tc-mips.c.

#define N_VFP   0xd4

Definition at line 516 of file tc-mips.c.

Definition at line 70 of file tc-mips.c.

#define NOP_INSN   (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn)

Definition at line 630 of file tc-mips.c.

Value:
{"$t0",       RTYPE_GP | 8},  \
    {"$t1",   RTYPE_GP | 9},  \
    {"$t2",   RTYPE_GP | 10}, \
    {"$t3",   RTYPE_GP | 11}, \
    {"$t4",   RTYPE_GP | 12}, \
    {"$t5",   RTYPE_GP | 13}, \
    {"$t6",   RTYPE_GP | 14}, \
    {"$t7",   RTYPE_GP | 15}, \
    {"$ta0",  RTYPE_GP | 12}, /* alias for $t4 */ \
    {"$ta1",  RTYPE_GP | 13}, /* alias for $t5 */ \
    {"$ta2",  RTYPE_GP | 14}, /* alias for $t6 */ \
    {"$ta3",  RTYPE_GP | 15}  /* alias for $t7 */

Definition at line 1563 of file tc-mips.c.

#define OPTION_ASE_BASE   (OPTION_ARCH_BASE + 11)
#define OPTION_BREAK   (OPTION_MISC_BASE + 1)
#define OPTION_DSP   (OPTION_ASE_BASE + 6)
#define OPTION_DSPR2   (OPTION_ASE_BASE + 12)
#define OPTION_EB   (OPTION_MISC_BASE + 2)
#define OPTION_EL   (OPTION_MISC_BASE + 3)
#define OPTION_FIX_VR4120   (OPTION_FIX_BASE + 2)
#define OPTION_FIX_VR4130   (OPTION_FIX_BASE + 4)
#define OPTION_FP32   (OPTION_MISC_BASE + 4)
#define OPTION_FP64   (OPTION_MISC_BASE + 8)
#define OPTION_GP32   (OPTION_MISC_BASE + 5)
#define OPTION_GP64   (OPTION_MISC_BASE + 9)
#define OPTION_MARCH   (OPTION_ARCH_BASE + 0)
#define OPTION_MDMX   (OPTION_ASE_BASE + 4)
#define OPTION_MIPS1   (OPTION_ARCH_BASE + 2)
#define OPTION_MIPS16   (OPTION_ASE_BASE + 0)
#define OPTION_MIPS2   (OPTION_ARCH_BASE + 3)
#define OPTION_MIPS3   (OPTION_ARCH_BASE + 4)
#define OPTION_MIPS32   (OPTION_ARCH_BASE + 7)
#define OPTION_MIPS32R2   (OPTION_ARCH_BASE + 9)
#define OPTION_MIPS3D   (OPTION_ASE_BASE + 2)
#define OPTION_MIPS4   (OPTION_ARCH_BASE + 5)
#define OPTION_MIPS5   (OPTION_ARCH_BASE + 6)
#define OPTION_MIPS64   (OPTION_ARCH_BASE + 8)
#define OPTION_MIPS64R2   (OPTION_ARCH_BASE + 10)
#define OPTION_MISC_BASE   (OPTION_FIX_BASE + 6)
#define OPTION_MNO_SHARED   (OPTION_MISC_BASE + 13)
#define OPTION_MNO_SYM32   (OPTION_MISC_BASE + 15)
#define OPTION_MSHARED   (OPTION_MISC_BASE + 12)
#define OPTION_MSYM32   (OPTION_MISC_BASE + 14)
#define OPTION_MT   (OPTION_ASE_BASE + 8)
#define OPTION_MTUNE   (OPTION_ARCH_BASE + 1)
#define OPTION_NO_DSP   (OPTION_ASE_BASE + 7)
#define OPTION_NO_DSPR2   (OPTION_ASE_BASE + 13)
#define OPTION_NO_MDMX   (OPTION_ASE_BASE + 5)
#define OPTION_NO_MIPS16   (OPTION_ASE_BASE + 1)
#define OPTION_NO_MIPS3D   (OPTION_ASE_BASE + 3)
#define OPTION_NO_MT   (OPTION_ASE_BASE + 9)
#define OPTION_NO_SMARTMIPS   (OPTION_ASE_BASE + 11)
#define OPTION_SMARTMIPS   (OPTION_ASE_BASE + 10)
#define OPTION_TRAP   (OPTION_MISC_BASE + 0)
#define PIC_CALL_REG   25

Definition at line 94 of file tc-mips.c.

#define RA   31

Definition at line 100 of file tc-mips.c.

Value:
(OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
                         ? ".rdata" \
                         : OUTPUT_FLAVOR == bfd_target_coff_flavour \
                         ? ".rdata" \
                         : OUTPUT_FLAVOR == bfd_target_elf_flavour \
                         ? ".rodata" \
                         : (abort (), ""))

Definition at line 113 of file tc-mips.c.

#define RELAX_BRANCH_ENCODE (   uncond,
  likely,
  link,
  toofar 
)
Value:
((relax_substateT) \
   (0xc0000000 \
    | ((toofar) ? 1 : 0) \
    | ((link) ? 2 : 0) \
    | ((likely) ? 4 : 0) \
    | ((uncond) ? 8 : 0)))

Definition at line 850 of file tc-mips.c.

#define RELAX_BRANCH_LIKELY (   i)    (((i) & 4) != 0)

Definition at line 859 of file tc-mips.c.

#define RELAX_BRANCH_LINK (   i)    (((i) & 2) != 0)

Definition at line 860 of file tc-mips.c.

#define RELAX_BRANCH_P (   i)    (((i) & 0xf0000000) == 0xc0000000)

Definition at line 857 of file tc-mips.c.

#define RELAX_BRANCH_TOOFAR (   i)    (((i) & 1) != 0)

Definition at line 861 of file tc-mips.c.

#define RELAX_BRANCH_UNCOND (   i)    (((i) & 8) != 0)

Definition at line 858 of file tc-mips.c.

#define RELAX_DELAY_SLOT   0x80000

Definition at line 781 of file tc-mips.c.

#define RELAX_ENCODE (   FIRST,
  SECOND 
)    (((FIRST) << 8) | (SECOND))

Definition at line 774 of file tc-mips.c.

#define RELAX_FIRST (   X)    (((X) >> 8) & 0xff)

Definition at line 776 of file tc-mips.c.

#define RELAX_MIPS16_CLEAR_EXTENDED (   i)    ((i) &~ 0x1000)

Definition at line 898 of file tc-mips.c.

#define RELAX_MIPS16_CLEAR_LONG_BRANCH (   i)    ((i) &~ 0x2000)

Definition at line 901 of file tc-mips.c.

#define RELAX_MIPS16_DSLOT (   i)    (((i) & 0x400) != 0)

Definition at line 894 of file tc-mips.c.

#define RELAX_MIPS16_ENCODE (   type,
  small,
  ext,
  dslot,
  jal_dslot 
)
Value:
(0x80000000                                             \
   | ((type) & 0xff)                                    \
   | ((small) ? 0x100 : 0)                              \
   | ((ext) ? 0x200 : 0)                                \
   | ((dslot) ? 0x400 : 0)                              \
   | ((jal_dslot) ? 0x800 : 0))

Definition at line 883 of file tc-mips.c.

#define RELAX_MIPS16_EXTENDED (   i)    (((i) & 0x1000) != 0)

Definition at line 896 of file tc-mips.c.

#define RELAX_MIPS16_JAL_DSLOT (   i)    (((i) & 0x800) != 0)

Definition at line 895 of file tc-mips.c.

#define RELAX_MIPS16_LONG_BRANCH (   i)    (((i) & 0x2000) != 0)

Definition at line 899 of file tc-mips.c.

#define RELAX_MIPS16_MARK_EXTENDED (   i)    ((i) | 0x1000)

Definition at line 897 of file tc-mips.c.

#define RELAX_MIPS16_MARK_LONG_BRANCH (   i)    ((i) | 0x2000)

Definition at line 900 of file tc-mips.c.

#define RELAX_MIPS16_P (   i)    (((i) & 0xc0000000) == 0x80000000)

Definition at line 890 of file tc-mips.c.

#define RELAX_MIPS16_TYPE (   i)    ((i) & 0xff)

Definition at line 891 of file tc-mips.c.

#define RELAX_MIPS16_USER_EXT (   i)    (((i) & 0x200) != 0)

Definition at line 893 of file tc-mips.c.

#define RELAX_MIPS16_USER_SMALL (   i)    (((i) & 0x100) != 0)

Definition at line 892 of file tc-mips.c.

#define RELAX_NOMACRO   0x40000

Definition at line 780 of file tc-mips.c.

#define RELAX_SECOND (   X)    ((X) & 0xff)

Definition at line 777 of file tc-mips.c.

#define RELAX_SECOND_LONGER   0x20000

Definition at line 779 of file tc-mips.c.

#define RELAX_USE_SECOND   0x10000

Definition at line 778 of file tc-mips.c.

#define RNUM_MASK   0x000ff

Definition at line 1458 of file tc-mips.c.

#define RTYPE_ACC   0x08000

Definition at line 1456 of file tc-mips.c.

#define RTYPE_CCC   0x10000

Definition at line 1457 of file tc-mips.c.

#define RTYPE_CP0   0x02000

Definition at line 1454 of file tc-mips.c.

#define RTYPE_FCC   0x00400

Definition at line 1451 of file tc-mips.c.

#define RTYPE_FPU   0x00200

Definition at line 1450 of file tc-mips.c.

#define RTYPE_GP   0x01000

Definition at line 1453 of file tc-mips.c.

#define RTYPE_MASK   0x1ff00

Definition at line 1448 of file tc-mips.c.

#define RTYPE_NUM   0x00100

Definition at line 1449 of file tc-mips.c.

#define RTYPE_PC   0x04000

Definition at line 1455 of file tc-mips.c.

#define RTYPE_VEC   0x00800

Definition at line 1452 of file tc-mips.c.

#define RWARN   0x80000

Definition at line 1459 of file tc-mips.c.

#define SKIP_SPACE_TABS (   S)    { while (*(S) == ' ' || *(S) == '\t') ++(S); }

Definition at line 9708 of file tc-mips.c.

#define SP   29

Definition at line 98 of file tc-mips.c.

Value:
{"$zero",     RTYPE_GP | 0},  \
    {"$at",   RTYPE_GP | 1},  \
    {"$AT",   RTYPE_GP | 1},  \
    {"$v0",   RTYPE_GP | 2},  \
    {"$v1",   RTYPE_GP | 3},  \
    {"$a0",   RTYPE_GP | 4},  \
    {"$a1",   RTYPE_GP | 5},  \
    {"$a2",   RTYPE_GP | 6},  \
    {"$a3",   RTYPE_GP | 7},  \
    {"$s0",   RTYPE_GP | 16}, \
    {"$s1",   RTYPE_GP | 17}, \
    {"$s2",   RTYPE_GP | 18}, \
    {"$s3",   RTYPE_GP | 19}, \
    {"$s4",   RTYPE_GP | 20}, \
    {"$s5",   RTYPE_GP | 21}, \
    {"$s6",   RTYPE_GP | 22}, \
    {"$s7",   RTYPE_GP | 23}, \
    {"$t8",   RTYPE_GP | 24}, \
    {"$t9",   RTYPE_GP | 25}, \
    {"$k0",   RTYPE_GP | 26}, \
    {"$kt0",  RTYPE_GP | 26}, \
    {"$k1",   RTYPE_GP | 27}, \
    {"$kt1",  RTYPE_GP | 27}, \
    {"$gp",   RTYPE_GP | 28}, \
    {"$sp",   RTYPE_GP | 29}, \
    {"$s8",   RTYPE_GP | 30}, \
    {"$fp",   RTYPE_GP | 30}, \
    {"$ra",   RTYPE_GP | 31}

Definition at line 1578 of file tc-mips.c.

#define TREG   24

Definition at line 93 of file tc-mips.c.

#define USE_BITS (   mask,
  shift 
)    (used_bits |= ((mask) << (shift)))

Definition at line 680 of file tc-mips.c.

#define ZERO   0

Definition at line 91 of file tc-mips.c.


Typedef Documentation

typedef struct proc procS

Enumeration Type Documentation

Enumerator:
FIX_VR4120_MACC 
FIX_VR4120_DMACC 
FIX_VR4120_MULT 
FIX_VR4120_DMULT 
FIX_VR4120_DIV 
FIX_VR4120_MTHILO 
NUM_FIX_VR4120_CLASSES 

Definition at line 699 of file tc-mips.c.

Enumerator:
NO_ABI 
O32_ABI 
O64_ABI 
N32_ABI 
N64_ABI 
EABI_ABI 

Definition at line 159 of file tc-mips.c.

Enumerator:
MIPS_GR_REG 
MIPS_FP_REG 
MIPS16_REG 

Definition at line 990 of file tc-mips.c.


Function Documentation

static void add_fixed_insn ( struct mips_cl_insn insn) [static]

Definition at line 1351 of file tc-mips.c.

{
  char *f = frag_more (insn_length (insn));
  move_insn (insn, frag_now, f - frag_now->fr_literal);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_got_offset ( int  dest,
expressionS local 
) [static]

Definition at line 4454 of file tc-mips.c.

{
  expressionS global;

  global.X_op = O_constant;
  global.X_op_symbol = NULL;
  global.X_add_symbol = NULL;
  global.X_add_number = local->X_add_number;

  relax_start (local->X_add_symbol);
  macro_build (&global, ADDRESS_ADDI_INSN, "t,r,j",
              dest, dest, BFD_RELOC_LO16);
  relax_switch ();
  macro_build (local, ADDRESS_ADDI_INSN, "t,r,j", dest, dest, BFD_RELOC_LO16);
  relax_end ();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_got_offset_hilo ( int  dest,
expressionS local,
int  tmp 
) [static]

Definition at line 4472 of file tc-mips.c.

{
  expressionS global;
  int hold_mips_optimize;

  global.X_op = O_constant;
  global.X_op_symbol = NULL;
  global.X_add_symbol = NULL;
  global.X_add_number = local->X_add_number;

  relax_start (local->X_add_symbol);
  load_register (tmp, &global, HAVE_64BIT_ADDRESSES);
  relax_switch ();
  /* Set mips_optimize around the lui instruction to avoid
     inserting an unnecessary nop after the lw.  */
  hold_mips_optimize = mips_optimize;
  mips_optimize = 2;
  macro_build_lui (&global, tmp);
  mips_optimize = hold_mips_optimize;
  macro_build (local, ADDRESS_ADDI_INSN, "t,r,j", tmp, tmp, BFD_RELOC_LO16);
  relax_end ();

  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dest, dest, tmp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_relaxed_insn ( struct mips_cl_insn insn,
int  max_chars,
int  var,
relax_substateT  subtype,
symbolS *  symbol,
offsetT  offset 
) [static]

Definition at line 1361 of file tc-mips.c.

{
  frag_grow (max_chars);
  move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal);
  insn->fixed_p = 1;
  frag_var (rs_machine_dependent, max_chars, var,
           subtype, symbol, offset, NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void append_insn ( struct mips_cl_insn ip,
expressionS p,
bfd_reloc_code_real_type r 
) [static]

Definition at line 2526 of file tc-mips.c.

{
  unsigned long prev_pinfo, pinfo;
  relax_stateT prev_insn_frag_type = 0;
  bfd_boolean relaxed_branch = FALSE;
  segment_info_type *si = seg_info (now_seg);

  /* Mark instruction labels in mips16 mode.  */
  mips16_mark_labels ();

  prev_pinfo = history[0].insn_mo->pinfo;
  pinfo = ip->insn_mo->pinfo;

  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
    {
      /* There are a lot of optimizations we could do that we don't.
        In particular, we do not, in general, reorder instructions.
        If you use gcc with optimization, it will reorder
        instructions and generally do much more optimization then we
        do here; repeating all that work in the assembler would only
        benefit hand written assembly code, and does not seem worth
        it.  */
      int nops = (mips_optimize == 0
                ? nops_for_insn (history, NULL)
                : nops_for_insn_or_target (history, ip));
      if (nops > 0)
       {
         fragS *old_frag;
         unsigned long old_frag_offset;
         int i;

         old_frag = frag_now;
         old_frag_offset = frag_now_fix ();

         for (i = 0; i < nops; i++)
           emit_nop ();

         if (listing)
           {
             listing_prev_line ();
             /* We may be at the start of a variant frag.  In case we
                 are, make sure there is enough space for the frag
                 after the frags created by listing_prev_line.  The
                 argument to frag_grow here must be at least as large
                 as the argument to all other calls to frag_grow in
                 this file.  We don't have to worry about being in the
                 middle of a variant frag, because the variants insert
                 all needed nop instructions themselves.  */
             frag_grow (40);
           }

         mips_move_labels ();

#ifndef NO_ECOFF_DEBUGGING
         if (ECOFF_DEBUGGING)
           ecoff_fix_loc (old_frag, old_frag_offset);
#endif
       }
    }
  else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
    {
      /* Work out how many nops in prev_nop_frag are needed by IP.  */
      int nops = nops_for_insn_or_target (history, ip);
      assert (nops <= prev_nop_frag_holds);

      /* Enforce NOPS as a minimum.  */
      if (nops > prev_nop_frag_required)
       prev_nop_frag_required = nops;

      if (prev_nop_frag_holds == prev_nop_frag_required)
       {
         /* Settle for the current number of nops.  Update the history
            accordingly (for the benefit of any future .set reorder code).  */
         prev_nop_frag = NULL;
         insert_into_history (prev_nop_frag_since,
                            prev_nop_frag_holds, NOP_INSN);
       }
      else
       {
         /* Allow this instruction to replace one of the nops that was
            tentatively added to prev_nop_frag.  */
         prev_nop_frag->fr_fix -= mips_opts.mips16 ? 2 : 4;
         prev_nop_frag_holds--;
         prev_nop_frag_since++;
       }
    }

#ifdef OBJ_ELF
  /* The value passed to dwarf2_emit_insn is the distance between
     the beginning of the current instruction and the address that
     should be recorded in the debug tables.  For MIPS16 debug info
     we want to use ISA-encoded addresses, so we pass -1 for an
     address higher by one than the current.  */
  dwarf2_emit_insn (mips_opts.mips16 ? -1 : 0);
#endif

  /* Record the frag type before frag_var.  */
  if (history[0].frag)
    prev_insn_frag_type = history[0].frag->fr_type;

  if (address_expr
      && *reloc_type == BFD_RELOC_16_PCREL_S2
      && (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
         || pinfo & INSN_COND_BRANCH_LIKELY)
      && mips_relax_branch
      /* Don't try branch relaxation within .set nomacro, or within
        .set noat if we use $at for PIC computations.  If it turns
        out that the branch was out-of-range, we'll get an error.  */
      && !mips_opts.warn_about_macros
      && !(mips_opts.noat && mips_pic != NO_PIC)
      && !mips_opts.mips16)
    {
      relaxed_branch = TRUE;
      add_relaxed_insn (ip, (relaxed_branch_length
                          (NULL, NULL,
                           (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
                           : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
                           : 0)), 4,
                     RELAX_BRANCH_ENCODE
                     (pinfo & INSN_UNCOND_BRANCH_DELAY,
                      pinfo & INSN_COND_BRANCH_LIKELY,
                      pinfo & INSN_WRITE_GPR_31,
                      0),
                     address_expr->X_add_symbol,
                     address_expr->X_add_number);
      *reloc_type = BFD_RELOC_UNUSED;
    }
  else if (*reloc_type > BFD_RELOC_UNUSED)
    {
      /* We need to set up a variant frag.  */
      assert (mips_opts.mips16 && address_expr != NULL);
      add_relaxed_insn (ip, 4, 0,
                     RELAX_MIPS16_ENCODE
                     (*reloc_type - BFD_RELOC_UNUSED,
                      mips16_small, mips16_ext,
                      prev_pinfo & INSN_UNCOND_BRANCH_DELAY,
                      history[0].mips16_absolute_jump_p),
                     make_expr_symbol (address_expr), 0);
    }
  else if (mips_opts.mips16
          && ! ip->use_extend
          && *reloc_type != BFD_RELOC_MIPS16_JMP)
    {
      if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
       /* Make sure there is enough room to swap this instruction with
          a following jump instruction.  */
       frag_grow (6);
      add_fixed_insn (ip);
    }
  else
    {
      if (mips_opts.mips16
         && mips_opts.noreorder
         && (prev_pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
       as_warn (_("extended instruction in delay slot"));

      if (mips_relax.sequence)
       {
         /* If we've reached the end of this frag, turn it into a variant
            frag and record the information for the instructions we've
            written so far.  */
         if (frag_room () < 4)
           relax_close_frag ();
         mips_relax.sizes[mips_relax.sequence - 1] += 4;
       }

      if (mips_relax.sequence != 2)
       mips_macro_warning.sizes[0] += 4;
      if (mips_relax.sequence != 1)
       mips_macro_warning.sizes[1] += 4;

      if (mips_opts.mips16)
       {
         ip->fixed_p = 1;
         ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP);
       }
      add_fixed_insn (ip);
    }

  if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
    {
      if (address_expr->X_op == O_constant)
       {
         unsigned int tmp;

         switch (*reloc_type)
           {
           case BFD_RELOC_32:
             ip->insn_opcode |= address_expr->X_add_number;
             break;

           case BFD_RELOC_MIPS_HIGHEST:
             tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
             ip->insn_opcode |= tmp & 0xffff;
             break;

           case BFD_RELOC_MIPS_HIGHER:
             tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
             ip->insn_opcode |= tmp & 0xffff;
             break;

           case BFD_RELOC_HI16_S:
             tmp = (address_expr->X_add_number + 0x8000) >> 16;
             ip->insn_opcode |= tmp & 0xffff;
             break;

           case BFD_RELOC_HI16:
             ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
             break;

           case BFD_RELOC_UNUSED:
           case BFD_RELOC_LO16:
           case BFD_RELOC_MIPS_GOT_DISP:
             ip->insn_opcode |= address_expr->X_add_number & 0xffff;
             break;

           case BFD_RELOC_MIPS_JMP:
             if ((address_expr->X_add_number & 3) != 0)
              as_bad (_("jump to misaligned address (0x%lx)"),
                     (unsigned long) address_expr->X_add_number);
             ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
             break;

           case BFD_RELOC_MIPS16_JMP:
             if ((address_expr->X_add_number & 3) != 0)
              as_bad (_("jump to misaligned address (0x%lx)"),
                     (unsigned long) address_expr->X_add_number);
             ip->insn_opcode |=
              (((address_expr->X_add_number & 0x7c0000) << 3)
               | ((address_expr->X_add_number & 0xf800000) >> 7)
               | ((address_expr->X_add_number & 0x3fffc) >> 2));
             break;

           case BFD_RELOC_16_PCREL_S2:
             if ((address_expr->X_add_number & 3) != 0)
              as_bad (_("branch to misaligned address (0x%lx)"),
                     (unsigned long) address_expr->X_add_number);
             if (mips_relax_branch)
              goto need_reloc;
             if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
              as_bad (_("branch address range overflow (0x%lx)"),
                     (unsigned long) address_expr->X_add_number);
             ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
             break;

           default:
             internalError ();
           }
       }
      else if (*reloc_type < BFD_RELOC_UNUSED)
       need_reloc:
       {
         reloc_howto_type *howto;
         int i;

         /* In a compound relocation, it is the final (outermost)
            operator that determines the relocated field.  */
         for (i = 1; i < 3; i++)
           if (reloc_type[i] == BFD_RELOC_UNUSED)
             break;

         howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
         ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
                                 bfd_get_reloc_size (howto),
                                 address_expr,
                                 reloc_type[0] == BFD_RELOC_16_PCREL_S2,
                                 reloc_type[0]);

         /* These relocations can have an addend that won't fit in
            4 octets for 64bit assembly.  */
         if (HAVE_64BIT_GPRS
             && ! howto->partial_inplace
             && (reloc_type[0] == BFD_RELOC_16
                || reloc_type[0] == BFD_RELOC_32
                || reloc_type[0] == BFD_RELOC_MIPS_JMP
                || reloc_type[0] == BFD_RELOC_HI16_S
                || reloc_type[0] == BFD_RELOC_LO16
                || reloc_type[0] == BFD_RELOC_GPREL16
                || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
                || reloc_type[0] == BFD_RELOC_GPREL32
                || reloc_type[0] == BFD_RELOC_64
                || reloc_type[0] == BFD_RELOC_CTOR
                || reloc_type[0] == BFD_RELOC_MIPS_SUB
                || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
                || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
                || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
                || reloc_type[0] == BFD_RELOC_MIPS_REL16
                || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
                || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
                || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
                || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
           ip->fixp[0]->fx_no_overflow = 1;

         if (mips_relax.sequence)
           {
             if (mips_relax.first_fixup == 0)
              mips_relax.first_fixup = ip->fixp[0];
           }
         else if (reloc_needs_lo_p (*reloc_type))
           {
             struct mips_hi_fixup *hi_fixup;

             /* Reuse the last entry if it already has a matching %lo.  */
             hi_fixup = mips_hi_fixup_list;
             if (hi_fixup == 0
                || !fixup_has_matching_lo_p (hi_fixup->fixp))
              {
                hi_fixup = ((struct mips_hi_fixup *)
                           xmalloc (sizeof (struct mips_hi_fixup)));
                hi_fixup->next = mips_hi_fixup_list;
                mips_hi_fixup_list = hi_fixup;
              }
             hi_fixup->fixp = ip->fixp[0];
             hi_fixup->seg = now_seg;
           }

         /* Add fixups for the second and third relocations, if given.
            Note that the ABI allows the second relocation to be
            against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the
            moment we only use RSS_UNDEF, but we could add support
            for the others if it ever becomes necessary.  */
         for (i = 1; i < 3; i++)
           if (reloc_type[i] != BFD_RELOC_UNUSED)
             {
              ip->fixp[i] = fix_new (ip->frag, ip->where,
                                   ip->fixp[0]->fx_size, NULL, 0,
                                   FALSE, reloc_type[i]);

              /* Use fx_tcbit to mark compound relocs.  */
              ip->fixp[0]->fx_tcbit = 1;
              ip->fixp[i]->fx_tcbit = 1;
             }
       }
    }
  install_insn (ip);

  /* Update the register mask information.  */
  if (! mips_opts.mips16)
    {
      if (pinfo & INSN_WRITE_GPR_D)
       mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
      if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
       mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
      if (pinfo & INSN_READ_GPR_S)
       mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
      if (pinfo & INSN_WRITE_GPR_31)
       mips_gprmask |= 1 << RA;
      if (pinfo & INSN_WRITE_FPR_D)
       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FD, *ip);
      if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FS, *ip);
      if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FT, *ip);
      if ((pinfo & INSN_READ_FPR_R) != 0)
       mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FR, *ip);
      if (pinfo & INSN_COP)
       {
         /* We don't keep enough information to sort these cases out.
            The itbl support does keep this information however, although
            we currently don't support itbl fprmats as part of the cop
            instruction.  May want to add this support in the future.  */
       }
      /* Never set the bit for $0, which is always zero.  */
      mips_gprmask &= ~1 << 0;
    }
  else
    {
      if (pinfo & (MIPS16_INSN_WRITE_X | MIPS16_INSN_READ_X))
       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
      if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
      if (pinfo & MIPS16_INSN_WRITE_Z)
       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
      if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
       mips_gprmask |= 1 << TREG;
      if (pinfo & (MIPS16_INSN_WRITE_SP | MIPS16_INSN_READ_SP))
       mips_gprmask |= 1 << SP;
      if (pinfo & (MIPS16_INSN_WRITE_31 | MIPS16_INSN_READ_31))
       mips_gprmask |= 1 << RA;
      if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
       mips_gprmask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
      if (pinfo & MIPS16_INSN_READ_Z)
       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip);
      if (pinfo & MIPS16_INSN_READ_GPR_X)
       mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
    }

  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
    {
      /* Filling the branch delay slot is more complex.  We try to
        switch the branch with the previous instruction, which we can
        do if the previous instruction does not set up a condition
        that the branch tests and if the branch is not itself the
        target of any branch.  */
      if ((pinfo & INSN_UNCOND_BRANCH_DELAY)
         || (pinfo & INSN_COND_BRANCH_DELAY))
       {
         if (mips_optimize < 2
             /* If we have seen .set volatile or .set nomove, don't
               optimize.  */
             || mips_opts.nomove != 0
             /* We can't swap if the previous instruction's position
               is fixed.  */
             || history[0].fixed_p
             /* If the previous previous insn was in a .set
               noreorder, we can't swap.  Actually, the MIPS
               assembler will swap in this situation.  However, gcc
               configured -with-gnu-as will generate code like
                 .set noreorder
                 lw  $4,XXX
                 .set       reorder
                 INSN
                 bne $4,$0,foo
               in which we can not swap the bne and INSN.  If gcc is
               not configured -with-gnu-as, it does not output the
               .set pseudo-ops.  */
             || history[1].noreorder_p
             /* If the branch is itself the target of a branch, we
               can not swap.  We cheat on this; all we check for is
               whether there is a label on this instruction.  If
               there are any branches to anything other than a
               label, users must use .set noreorder.  */
             || si->label_list != NULL
             /* If the previous instruction is in a variant frag
               other than this branch's one, we cannot do the swap.
               This does not apply to the mips16, which uses variant
               frags for different purposes.  */
             || (! mips_opts.mips16
                && prev_insn_frag_type == rs_machine_dependent)
             /* Check for conflicts between the branch and the instructions
               before the candidate delay slot.  */
             || nops_for_insn (history + 1, ip) > 0
             /* Check for conflicts between the swapped sequence and the
               target of the branch.  */
             || nops_for_sequence (2, history + 1, ip, history) > 0
             /* We do not swap with a trap instruction, since it
               complicates trap handlers to have the trap
               instruction be in a delay slot.  */
             || (prev_pinfo & INSN_TRAP)
             /* If the branch reads a register that the previous
               instruction sets, we can not swap.  */
             || (! mips_opts.mips16
                && (prev_pinfo & INSN_WRITE_GPR_T)
                && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
                                MIPS_GR_REG))
             || (! mips_opts.mips16
                && (prev_pinfo & INSN_WRITE_GPR_D)
                && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
                                MIPS_GR_REG))
             || (mips_opts.mips16
                && (((prev_pinfo & MIPS16_INSN_WRITE_X)
                     && (insn_uses_reg
                        (ip, MIPS16_EXTRACT_OPERAND (RX, history[0]),
                         MIPS16_REG)))
                    || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
                       && (insn_uses_reg
                           (ip, MIPS16_EXTRACT_OPERAND (RY, history[0]),
                            MIPS16_REG)))
                    || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
                       && (insn_uses_reg
                           (ip, MIPS16_EXTRACT_OPERAND (RZ, history[0]),
                            MIPS16_REG)))
                    || ((prev_pinfo & MIPS16_INSN_WRITE_T)
                       && insn_uses_reg (ip, TREG, MIPS_GR_REG))
                    || ((prev_pinfo & MIPS16_INSN_WRITE_31)
                       && insn_uses_reg (ip, RA, MIPS_GR_REG))
                    || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
                       && insn_uses_reg (ip,
                                       MIPS16OP_EXTRACT_REG32R
                                         (history[0].insn_opcode),
                                       MIPS_GR_REG))))
             /* If the branch writes a register that the previous
               instruction sets, we can not swap (we know that
               branches write only to RD or to $31).  */
             || (! mips_opts.mips16
                && (prev_pinfo & INSN_WRITE_GPR_T)
                && (((pinfo & INSN_WRITE_GPR_D)
                     && (EXTRACT_OPERAND (RT, history[0])
                        == EXTRACT_OPERAND (RD, *ip)))
                    || ((pinfo & INSN_WRITE_GPR_31)
                       && EXTRACT_OPERAND (RT, history[0]) == RA)))
             || (! mips_opts.mips16
                && (prev_pinfo & INSN_WRITE_GPR_D)
                && (((pinfo & INSN_WRITE_GPR_D)
                     && (EXTRACT_OPERAND (RD, history[0])
                        == EXTRACT_OPERAND (RD, *ip)))
                    || ((pinfo & INSN_WRITE_GPR_31)
                       && EXTRACT_OPERAND (RD, history[0]) == RA)))
             || (mips_opts.mips16
                && (pinfo & MIPS16_INSN_WRITE_31)
                && ((prev_pinfo & MIPS16_INSN_WRITE_31)
                    || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
                       && (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
                           == RA))))
             /* If the branch writes a register that the previous
               instruction reads, we can not swap (we know that
               branches only write to RD or to $31).  */
             || (! mips_opts.mips16
                && (pinfo & INSN_WRITE_GPR_D)
                && insn_uses_reg (&history[0],
                                EXTRACT_OPERAND (RD, *ip),
                                MIPS_GR_REG))
             || (! mips_opts.mips16
                && (pinfo & INSN_WRITE_GPR_31)
                && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
             || (mips_opts.mips16
                && (pinfo & MIPS16_INSN_WRITE_31)
                && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
             /* If one instruction sets a condition code and the
                 other one uses a condition code, we can not swap.  */
             || ((pinfo & INSN_READ_COND_CODE)
                && (prev_pinfo & INSN_WRITE_COND_CODE))
             || ((pinfo & INSN_WRITE_COND_CODE)
                && (prev_pinfo & INSN_READ_COND_CODE))
             /* If the previous instruction uses the PC, we can not
                 swap.  */
             || (mips_opts.mips16
                && (prev_pinfo & MIPS16_INSN_READ_PC))
             /* If the previous instruction had a fixup in mips16
                 mode, we can not swap.  This normally means that the
                 previous instruction was a 4 byte branch anyhow.  */
             || (mips_opts.mips16 && history[0].fixp[0])
             /* If the previous instruction is a sync, sync.l, or
               sync.p, we can not swap.  */
             || (prev_pinfo & INSN_SYNC))
           {
             if (mips_opts.mips16
                && (pinfo & INSN_UNCOND_BRANCH_DELAY)
                && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31))
                && ISA_SUPPORTS_MIPS16E)
              {
                /* Convert MIPS16 jr/jalr into a "compact" jump.  */
                ip->insn_opcode |= 0x0080;
                install_insn (ip);
                insert_into_history (0, 1, ip);
              } 
             else
              {
                /* We could do even better for unconditional branches to
                   portions of this object file; we could pick up the
                   instruction at the destination, put it in the delay
                   slot, and bump the destination address.  */
                insert_into_history (0, 1, ip);
                emit_nop ();
              }
              
             if (mips_relax.sequence)
              mips_relax.sizes[mips_relax.sequence - 1] += 4;
           }
         else
           {
             /* It looks like we can actually do the swap.  */
             struct mips_cl_insn delay = history[0];
             if (mips_opts.mips16)
              {
                know (delay.frag == ip->frag);
                  move_insn (ip, delay.frag, delay.where);
                move_insn (&delay, ip->frag, ip->where + insn_length (ip));
              }
             else if (relaxed_branch)
              {
                /* Add the delay slot instruction to the end of the
                   current frag and shrink the fixed part of the
                   original frag.  If the branch occupies the tail of
                   the latter, move it backwards to cover the gap.  */
                delay.frag->fr_fix -= 4;
                if (delay.frag == ip->frag)
                  move_insn (ip, ip->frag, ip->where - 4);
                add_fixed_insn (&delay);
              }
             else
              {
                move_insn (&delay, ip->frag, ip->where);
                move_insn (ip, history[0].frag, history[0].where);
              }
             history[0] = *ip;
             delay.fixed_p = 1;
             insert_into_history (0, 1, &delay);
           }

         /* If that was an unconditional branch, forget the previous
            insn information.  */
         if (pinfo & INSN_UNCOND_BRANCH_DELAY)
           mips_no_prev_insn ();
       }
      else if (pinfo & INSN_COND_BRANCH_LIKELY)
       {
         /* We don't yet optimize a branch likely.  What we should do
            is look at the target, copy the instruction found there
            into the delay slot, and increment the branch to jump to
            the next instruction.  */
         insert_into_history (0, 1, ip);
         emit_nop ();
       }
      else
       insert_into_history (0, 1, ip);
    }
  else
    insert_into_history (0, 1, ip);

  /* We just output an insn, so the next one doesn't have a label.  */
  mips_clear_insn_labels ();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_absolute_expr ( struct mips_cl_insn ip,
expressionS ex 
) [static]

Definition at line 3836 of file tc-mips.c.

{
  if (ex->X_op == O_big)
    as_bad (_("unsupported large constant"));
  else if (ex->X_op != O_constant)
    as_bad (_("Instruction %s requires absolute expression"),
           ip->insn_mo->name);

  if (HAVE_32BIT_GPRS)
    normalize_constant_expr (ex);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned int classify_vr4120_insn ( const char *  name) [static]

Definition at line 2259 of file tc-mips.c.

{
  if (strncmp (name, "macc", 4) == 0)
    return FIX_VR4120_MACC;
  if (strncmp (name, "dmacc", 5) == 0)
    return FIX_VR4120_DMACC;
  if (strncmp (name, "mult", 4) == 0)
    return FIX_VR4120_MULT;
  if (strncmp (name, "dmult", 5) == 0)
    return FIX_VR4120_DMULT;
  if (strstr (name, "div"))
    return FIX_VR4120_DIV;
  if (strcmp (name, "mtlo") == 0 || strcmp (name, "mthi") == 0)
    return FIX_VR4120_MTHILO;
  return NUM_FIX_VR4120_CLASSES;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void create_insn ( struct mips_cl_insn insn,
const struct mips_opcode mo 
) [static]

Definition at line 1288 of file tc-mips.c.

{
  size_t i;

  insn->insn_mo = mo;
  insn->use_extend = FALSE;
  insn->extend = 0;
  insn->insn_opcode = mo->match;
  insn->frag = NULL;
  insn->where = 0;
  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
    insn->fixp[i] = NULL;
  insn->fixed_p = (mips_opts.noreorder > 0);
  insn->noreorder_p = (mips_opts.noreorder > 0);
  insn->mips16_absolute_jump_p = 0;
}

Here is the caller graph for this function:

static void emit_nop ( void  ) [static]

Definition at line 1393 of file tc-mips.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void end_noreorder ( void  ) [static]

Definition at line 3211 of file tc-mips.c.

{
  mips_opts.noreorder--;
  if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
    {
      /* Commit to inserting prev_nop_frag_required nops and go back to
        handling nop insertion the .set reorder way.  */
      prev_nop_frag->fr_fix -= ((prev_nop_frag_holds - prev_nop_frag_required)
                            * (mips_opts.mips16 ? 2 : 4));
      insert_into_history (prev_nop_frag_since,
                        prev_nop_frag_required, NOP_INSN);
      prev_nop_frag = NULL;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean fixup_has_matching_lo_p ( fixS *  fixp) [inline, static]

Definition at line 2021 of file tc-mips.c.

{
  return (fixp->fx_next != NULL
         && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
            || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
         && fixp->fx_addsy == fixp->fx_next->fx_addsy
         && fixp->fx_offset == fixp->fx_next->fx_offset);
}

Here is the caller graph for this function:

static long get_number ( void  ) [static]

Definition at line 14286 of file tc-mips.c.

{
  int negative = 0;
  long val = 0;

  if (*input_line_pointer == '-')
    {
      ++input_line_pointer;
      negative = 1;
    }
  if (!ISDIGIT (*input_line_pointer))
    as_bad (_("expected simple number"));
  if (input_line_pointer[0] == '0')
    {
      if (input_line_pointer[1] == 'x')
       {
         input_line_pointer += 2;
         while (ISXDIGIT (*input_line_pointer))
           {
             val <<= 4;
             val |= hex_value (*input_line_pointer++);
           }
         return negative ? -val : val;
       }
      else
       {
         ++input_line_pointer;
         while (ISDIGIT (*input_line_pointer))
           {
             val <<= 3;
             val |= *input_line_pointer++ - '0';
           }
         return negative ? -val : val;
       }
    }
  if (!ISDIGIT (*input_line_pointer))
    {
      printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
             *input_line_pointer, *input_line_pointer);
      as_warn (_("invalid number"));
      return -1;
    }
  while (ISDIGIT (*input_line_pointer))
    {
      val *= 10;
      val += *input_line_pointer++ - '0';
    }
  return negative ? -val : val;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static symbolS* get_symbol ( void  ) [static]

Definition at line 12000 of file tc-mips.c.

{
  int c;
  char *name;
  symbolS *p;

  name = input_line_pointer;
  c = get_symbol_end ();
  p = (symbolS *) symbol_find_or_make (name);
  *input_line_pointer = c;
  return p;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void init_vr4120_conflicts ( void  ) [static]

Definition at line 1404 of file tc-mips.c.

{
#define CONFLICT(FIRST, SECOND) \
    vr4120_conflicts[FIX_VR4120_##FIRST] |= 1 << FIX_VR4120_##SECOND

  /* Errata 21 - [D]DIV[U] after [D]MACC */
  CONFLICT (MACC, DIV);
  CONFLICT (DMACC, DIV);

  /* Errata 23 - Continuous DMULT[U]/DMACC instructions.  */
  CONFLICT (DMULT, DMULT);
  CONFLICT (DMULT, DMACC);
  CONFLICT (DMACC, DMULT);
  CONFLICT (DMACC, DMACC);

  /* Errata 24 - MT{LO,HI} after [D]MACC */
  CONFLICT (MACC, MTHILO);
  CONFLICT (DMACC, MTHILO);

  /* VR4181A errata MD(1): "If a MULT, MULTU, DMULT or DMULTU
     instruction is executed immediately after a MACC or DMACC
     instruction, the result of [either instruction] is incorrect."  */
  CONFLICT (MACC, MULT);
  CONFLICT (MACC, DMULT);
  CONFLICT (DMACC, MULT);
  CONFLICT (DMACC, DMULT);

  /* VR4181A errata MD(4): "If a MACC or DMACC instruction is
     executed immediately after a DMULT, DMULTU, DIV, DIVU,
     DDIV or DDIVU instruction, the result of the MACC or
     DMACC instruction is incorrect.".  */
  CONFLICT (DMULT, MACC);
  CONFLICT (DMULT, DMACC);
  CONFLICT (DIV, MACC);
  CONFLICT (DIV, DMACC);

#undef CONFLICT
}

Here is the caller graph for this function:

static void insert_into_history ( unsigned int  first,
unsigned int  n,
const struct mips_cl_insn insn 
) [static]

Definition at line 1375 of file tc-mips.c.

{
  if (mips_relax.sequence != 2)
    {
      unsigned int i;

      for (i = ARRAY_SIZE (history); i-- > first;)
       if (i >= first + n)
         history[i] = history[i - n];
       else
         history[i] = *insn;
    }
}

Here is the caller graph for this function:

static unsigned int insn_length ( const struct mips_cl_insn insn) [inline, static]

Definition at line 1278 of file tc-mips.c.

{
  if (!mips_opts.mips16)
    return 4;
  return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
}

Here is the caller graph for this function:

static int insn_uses_reg ( const struct mips_cl_insn ip,
unsigned int  reg,
enum mips_regclass  class 
) [static]

Definition at line 2034 of file tc-mips.c.

{
  if (class == MIPS16_REG)
    {
      assert (mips_opts.mips16);
      reg = mips16_to_32_reg_map[reg];
      class = MIPS_GR_REG;
    }

  /* Don't report on general register ZERO, since it never changes.  */
  if (class == MIPS_GR_REG && reg == ZERO)
    return 0;

  if (class == MIPS_FP_REG)
    {
      assert (! mips_opts.mips16);
      /* If we are called with either $f0 or $f1, we must check $f0.
        This is not optimal, because it will introduce an unnecessary
        NOP between "lwc1 $f0" and "swc1 $f1".  To fix this we would
        need to distinguish reading both $f0 and $f1 or just one of
        them.  Note that we don't have to check the other way,
        because there is no instruction that sets both $f0 and $f1
        and requires a delay.  */
      if ((ip->insn_mo->pinfo & INSN_READ_FPR_S)
         && ((EXTRACT_OPERAND (FS, *ip) & ~(unsigned) 1)
             == (reg &~ (unsigned) 1)))
       return 1;
      if ((ip->insn_mo->pinfo & INSN_READ_FPR_T)
         && ((EXTRACT_OPERAND (FT, *ip) & ~(unsigned) 1)
             == (reg &~ (unsigned) 1)))
       return 1;
    }
  else if (! mips_opts.mips16)
    {
      if ((ip->insn_mo->pinfo & INSN_READ_GPR_S)
         && EXTRACT_OPERAND (RS, *ip) == reg)
       return 1;
      if ((ip->insn_mo->pinfo & INSN_READ_GPR_T)
         && EXTRACT_OPERAND (RT, *ip) == reg)
       return 1;
    }
  else
    {
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_X)
         && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)] == reg)
       return 1;
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Y)
         && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)] == reg)
       return 1;
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Z)
         && (mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]
             == reg))
       return 1;
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_T) && reg == TREG)
       return 1;
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_SP) && reg == SP)
       return 1;
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_31) && reg == RA)
       return 1;
      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_GPR_X)
         && MIPS16_EXTRACT_OPERAND (REGR32, *ip) == reg)
       return 1;
    }

  return 0;
}

Here is the caller graph for this function:

static unsigned int insns_between ( const struct mips_cl_insn insn1,
const struct mips_cl_insn insn2 
) [static]

Definition at line 2281 of file tc-mips.c.

{
  unsigned long pinfo1, pinfo2;

  /* This function needs to know which pinfo flags are set for INSN2
     and which registers INSN2 uses.  The former is stored in PINFO2 and
     the latter is tested via INSN2_USES_REG.  If INSN2 is null, PINFO2
     will have every flag set and INSN2_USES_REG will always return true.  */
  pinfo1 = insn1->insn_mo->pinfo;
  pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;

#define INSN2_USES_REG(REG, CLASS) \
   (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))

  /* For most targets, write-after-read dependencies on the HI and LO
     registers must be separated by at least two instructions.  */
  if (!hilo_interlocks)
    {
      if ((pinfo1 & INSN_READ_LO) && (pinfo2 & INSN_WRITE_LO))
       return 2;
      if ((pinfo1 & INSN_READ_HI) && (pinfo2 & INSN_WRITE_HI))
       return 2;
    }

  /* If we're working around r7000 errata, there must be two instructions
     between an mfhi or mflo and any instruction that uses the result.  */
  if (mips_7000_hilo_fix
      && MF_HILO_INSN (pinfo1)
      && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
    return 2;

  /* If working around VR4120 errata, check for combinations that need
     a single intervening instruction.  */
  if (mips_fix_vr4120)
    {
      unsigned int class1, class2;

      class1 = classify_vr4120_insn (insn1->insn_mo->name);
      if (class1 != NUM_FIX_VR4120_CLASSES && vr4120_conflicts[class1] != 0)
       {
         if (insn2 == NULL)
           return 1;
         class2 = classify_vr4120_insn (insn2->insn_mo->name);
         if (vr4120_conflicts[class1] & (1 << class2))
           return 1;
       }
    }

  if (!mips_opts.mips16)
    {
      /* Check for GPR or coprocessor load delays.  All such delays
        are on the RT register.  */
      /* Itbl support may require additional care here.  */
      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
         || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
       {
         know (pinfo1 & INSN_WRITE_GPR_T);
         if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
           return 1;
       }

      /* Check for generic coprocessor hazards.

        This case is not handled very well.  There is no special
        knowledge of CP0 handling, and the coprocessors other than
        the floating point unit are not distinguished at all.  */
      /* Itbl support may require additional care here. FIXME!
        Need to modify this to include knowledge about
        user specified delays!  */
      else if ((!cop_interlocks && (pinfo1 & INSN_COPROC_MOVE_DELAY))
              || (!cop_mem_interlocks && (pinfo1 & INSN_COPROC_MEMORY_DELAY)))
       {
         /* Handle cases where INSN1 writes to a known general coprocessor
            register.  There must be a one instruction delay before INSN2
            if INSN2 reads that register, otherwise no delay is needed.  */
         if (pinfo1 & INSN_WRITE_FPR_T)
           {
             if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
              return 1;
           }
         else if (pinfo1 & INSN_WRITE_FPR_S)
           {
             if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
              return 1;
           }
         else
           {
             /* Read-after-write dependencies on the control registers
               require a two-instruction gap.  */
             if ((pinfo1 & INSN_WRITE_COND_CODE)
                && (pinfo2 & INSN_READ_COND_CODE))
              return 2;

             /* We don't know exactly what INSN1 does.  If INSN2 is
               also a coprocessor instruction, assume there must be
               a one instruction gap.  */
             if (pinfo2 & INSN_COP)
              return 1;
           }
       }

      /* Check for read-after-write dependencies on the coprocessor
        control registers in cases where INSN1 does not need a general
        coprocessor delay.  This means that INSN1 is a floating point
        comparison instruction.  */
      /* Itbl support may require additional care here.  */
      else if (!cop_interlocks
              && (pinfo1 & INSN_WRITE_COND_CODE)
              && (pinfo2 & INSN_READ_COND_CODE))
       return 1;
    }

#undef INSN2_USES_REG

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void install_insn ( const struct mips_cl_insn insn) [static]

Definition at line 1308 of file tc-mips.c.

{
  char *f = insn->frag->fr_literal + insn->where;
  if (!mips_opts.mips16)
    md_number_to_chars (f, insn->insn_opcode, 4);
  else if (insn->mips16_absolute_jump_p)
    {
      md_number_to_chars (f, insn->insn_opcode >> 16, 2);
      md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
    }
  else
    {
      if (insn->use_extend)
       {
         md_number_to_chars (f, 0xf000 | insn->extend, 2);
         f += 2;
       }
      md_number_to_chars (f, insn->insn_opcode, 2);
    }
}

Here is the caller graph for this function:

static void load_address ( int  reg,
expressionS ep,
int used_at 
) [static]

Definition at line 4166 of file tc-mips.c.

{
  if (ep->X_op != O_constant
      && ep->X_op != O_symbol)
    {
      as_bad (_("expression too complex"));
      ep->X_op = O_constant;
    }

  if (ep->X_op == O_constant)
    {
      load_register (reg, ep, HAVE_64BIT_ADDRESSES);
      return;
    }

  if (mips_pic == NO_PIC)
    {
      /* If this is a reference to a GP relative symbol, we want
          addiu      $reg,$gp,<sym>              (BFD_RELOC_GPREL16)
        Otherwise we want
          lui        $reg,<sym>           (BFD_RELOC_HI16_S)
          addiu      $reg,$reg,<sym>             (BFD_RELOC_LO16)
        If we have an addend, we always use the latter form.

        With 64bit address space and a usable $at we want
          lui        $reg,<sym>           (BFD_RELOC_MIPS_HIGHEST)
          lui        $at,<sym>            (BFD_RELOC_HI16_S)
          daddiu     $reg,<sym>           (BFD_RELOC_MIPS_HIGHER)
          daddiu     $at,<sym>            (BFD_RELOC_LO16)
          dsll32     $reg,0
          daddu      $reg,$reg,$at

        If $at is already in use, we use a path which is suboptimal
        on superscalar processors.
          lui        $reg,<sym>           (BFD_RELOC_MIPS_HIGHEST)
          daddiu     $reg,<sym>           (BFD_RELOC_MIPS_HIGHER)
          dsll              $reg,16
          daddiu     $reg,<sym>           (BFD_RELOC_HI16_S)
          dsll              $reg,16
          daddiu     $reg,<sym>           (BFD_RELOC_LO16)

        For GP relative symbols in 64bit address space we can use
        the same sequence as in 32bit address space.  */
      if (HAVE_64BIT_SYMBOLS)
       {
         if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET
             && !nopic_need_relax (ep->X_add_symbol, 1))
           {
             relax_start (ep->X_add_symbol);
             macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
                        mips_gp_register, BFD_RELOC_GPREL16);
             relax_switch ();
           }

         if (*used_at == 0 && !mips_opts.noat)
           {
             macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
             macro_build (ep, "lui", "t,u", AT, BFD_RELOC_HI16_S);
             macro_build (ep, "daddiu", "t,r,j", reg, reg,
                        BFD_RELOC_MIPS_HIGHER);
             macro_build (ep, "daddiu", "t,r,j", AT, AT, BFD_RELOC_LO16);
             macro_build (NULL, "dsll32", "d,w,<", reg, reg, 0);
             macro_build (NULL, "daddu", "d,v,t", reg, reg, AT);
             *used_at = 1;
           }
         else
           {
             macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
             macro_build (ep, "daddiu", "t,r,j", reg, reg,
                        BFD_RELOC_MIPS_HIGHER);
             macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
             macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_HI16_S);
             macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
             macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_LO16);
           }

         if (mips_relax.sequence)
           relax_end ();
       }
      else
       {
         if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET
             && !nopic_need_relax (ep->X_add_symbol, 1))
           {
             relax_start (ep->X_add_symbol);
             macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
                        mips_gp_register, BFD_RELOC_GPREL16);
             relax_switch ();
           }
         macro_build_lui (ep, reg);
         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j",
                     reg, reg, BFD_RELOC_LO16);
         if (mips_relax.sequence)
           relax_end ();
       }
    }
  else if (!mips_big_got)
    {
      expressionS ex;

      /* If this is a reference to an external symbol, we want
          lw         $reg,<sym>($gp)             (BFD_RELOC_MIPS_GOT16)
        Otherwise we want
          lw         $reg,<sym>($gp)             (BFD_RELOC_MIPS_GOT16)
          nop
          addiu      $reg,$reg,<sym>             (BFD_RELOC_LO16)
        If there is a constant, it must be added in after.

        If we have NewABI, we want
          lw         $reg,<sym+cst>($gp)  (BFD_RELOC_MIPS_GOT_DISP)
         unless we're referencing a global symbol with a non-zero
         offset, in which case cst must be added separately.  */
      if (HAVE_NEWABI)
       {
         if (ep->X_add_number)
           {
             ex.X_add_number = ep->X_add_number;
             ep->X_add_number = 0;
             relax_start (ep->X_add_symbol);
             macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                        BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
             if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
              as_bad (_("PIC code offset overflow (max 16 signed bits)"));
             ex.X_op = O_constant;
             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j",
                        reg, reg, BFD_RELOC_LO16);
             ep->X_add_number = ex.X_add_number;
             relax_switch ();
           }
         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                     BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
         if (mips_relax.sequence)
           relax_end ();
       }
      else
       {
         ex.X_add_number = ep->X_add_number;
         ep->X_add_number = 0;
         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                     BFD_RELOC_MIPS_GOT16, mips_gp_register);
         load_delay_nop ();
         relax_start (ep->X_add_symbol);
         relax_switch ();
         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                     BFD_RELOC_LO16);
         relax_end ();

         if (ex.X_add_number != 0)
           {
             if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
              as_bad (_("PIC code offset overflow (max 16 signed bits)"));
             ex.X_op = O_constant;
             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j",
                        reg, reg, BFD_RELOC_LO16);
           }
       }
    }
  else if (mips_big_got)
    {
      expressionS ex;

      /* This is the large GOT case.  If this is a reference to an
        external symbol, we want
          lui        $reg,<sym>           (BFD_RELOC_MIPS_GOT_HI16)
          addu              $reg,$reg,$gp
          lw         $reg,<sym>($reg)     (BFD_RELOC_MIPS_GOT_LO16)

        Otherwise, for a reference to a local symbol in old ABI, we want
          lw         $reg,<sym>($gp)             (BFD_RELOC_MIPS_GOT16)
          nop
          addiu      $reg,$reg,<sym>             (BFD_RELOC_LO16)
        If there is a constant, it must be added in after.

        In the NewABI, for local symbols, with or without offsets, we want:
          lw         $reg,<sym>($gp)             (BFD_RELOC_MIPS_GOT_PAGE)
          addiu      $reg,$reg,<sym>             (BFD_RELOC_MIPS_GOT_OFST)
      */
      if (HAVE_NEWABI)
       {
         ex.X_add_number = ep->X_add_number;
         ep->X_add_number = 0;
         relax_start (ep->X_add_symbol);
         macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                     reg, reg, mips_gp_register);
         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
                     reg, BFD_RELOC_MIPS_GOT_LO16, reg);
         if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
         else if (ex.X_add_number)
           {
             ex.X_op = O_constant;
             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                        BFD_RELOC_LO16);
           }

         ep->X_add_number = ex.X_add_number;
         relax_switch ();
         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                     BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                     BFD_RELOC_MIPS_GOT_OFST);
         relax_end ();
       }
      else
       {
         ex.X_add_number = ep->X_add_number;
         ep->X_add_number = 0;
         relax_start (ep->X_add_symbol);
         macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                     reg, reg, mips_gp_register);
         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
                     reg, BFD_RELOC_MIPS_GOT_LO16, reg);
         relax_switch ();
         if (reg_needs_delay (mips_gp_register))
           {
             /* We need a nop before loading from $gp.  This special
               check is required because the lui which starts the main
               instruction stream does not refer to $gp, and so will not
               insert the nop which may be required.  */
             macro_build (NULL, "nop", "");
           }
         macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
                     BFD_RELOC_MIPS_GOT16, mips_gp_register);
         load_delay_nop ();
         macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                     BFD_RELOC_LO16);
         relax_end ();

         if (ex.X_add_number != 0)
           {
             if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
              as_bad (_("PIC code offset overflow (max 16 signed bits)"));
             ex.X_op = O_constant;
             macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
                        BFD_RELOC_LO16);
           }
       }
    }
  else
    abort ();

  if (mips_opts.noat && *used_at == 1)
    as_bad (_("Macro used $at after \".set noat\""));
}

Here is the call graph for this function:

static void load_delay_nop ( void  ) [inline, static]

Definition at line 4157 of file tc-mips.c.

{
  if (!gpr_interlocks)
    macro_build (NULL, "nop", "");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void load_got_offset ( int  dest,
expressionS local 
) [static]

Definition at line 4437 of file tc-mips.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void load_register ( int  reg,
expressionS ep,
int  dbl 
) [static]

Definition at line 3929 of file tc-mips.c.

{
  int freg;
  expressionS hi32, lo32;

  if (ep->X_op != O_big)
    {
      assert (ep->X_op == O_constant);

      /* Sign-extending 32-bit constants makes their handling easier.  */
      if (!dbl)
       normalize_constant_expr (ep);

      if (IS_SEXT_16BIT_NUM (ep->X_add_number))
       {
         /* We can handle 16 bit signed values with an addiu to
            $zero.  No need to ever use daddiu here, since $zero and
            the result are always correct in 32 bit mode.  */
         macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
         return;
       }
      else if (ep->X_add_number >= 0 && ep->X_add_number < 0x10000)
       {
         /* We can handle 16 bit unsigned values with an ori to
             $zero.  */
         macro_build (ep, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
         return;
       }
      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
       {
         /* 32 bit values require an lui.  */
         macro_build (ep, "lui", "t,u", reg, BFD_RELOC_HI16);
         if ((ep->X_add_number & 0xffff) != 0)
           macro_build (ep, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
         return;
       }
    }

  /* The value is larger than 32 bits.  */

  if (!dbl || HAVE_32BIT_GPRS)
    {
      char value[32];

      sprintf_vma (value, ep->X_add_number);
      as_bad (_("Number (0x%s) larger than 32 bits"), value);
      macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
      return;
    }

  if (ep->X_op != O_big)
    {
      hi32 = *ep;
      hi32.X_add_number = (valueT) hi32.X_add_number >> 16;
      hi32.X_add_number = (valueT) hi32.X_add_number >> 16;
      hi32.X_add_number &= 0xffffffff;
      lo32 = *ep;
      lo32.X_add_number &= 0xffffffff;
    }
  else
    {
      assert (ep->X_add_number > 2);
      if (ep->X_add_number == 3)
       generic_bignum[3] = 0;
      else if (ep->X_add_number > 4)
       as_bad (_("Number larger than 64 bits"));
      lo32.X_op = O_constant;
      lo32.X_add_number = generic_bignum[0] + (generic_bignum[1] << 16);
      hi32.X_op = O_constant;
      hi32.X_add_number = generic_bignum[2] + (generic_bignum[3] << 16);
    }

  if (hi32.X_add_number == 0)
    freg = 0;
  else
    {
      int shift, bit;
      unsigned long hi, lo;

      if (hi32.X_add_number == (offsetT) 0xffffffff)
       {
         if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
           {
             macro_build (&lo32, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
             return;
           }
         if (lo32.X_add_number & 0x80000000)
           {
             macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
             if (lo32.X_add_number & 0xffff)
              macro_build (&lo32, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
             return;
           }
       }

      /* Check for 16bit shifted constant.  We know that hi32 is
         non-zero, so start the mask on the first bit of the hi32
         value.  */
      shift = 17;
      do
       {
         unsigned long himask, lomask;

         if (shift < 32)
           {
             himask = 0xffff >> (32 - shift);
             lomask = (0xffff << shift) & 0xffffffff;
           }
         else
           {
             himask = 0xffff << (shift - 32);
             lomask = 0;
           }
         if ((hi32.X_add_number & ~(offsetT) himask) == 0
             && (lo32.X_add_number & ~(offsetT) lomask) == 0)
           {
             expressionS tmp;

             tmp.X_op = O_constant;
             if (shift < 32)
              tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
                                | (lo32.X_add_number >> shift));
             else
              tmp.X_add_number = hi32.X_add_number >> (shift - 32);
             macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
             macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
                        reg, reg, (shift >= 32) ? shift - 32 : shift);
             return;
           }
         ++shift;
       }
      while (shift <= (64 - 16));

      /* Find the bit number of the lowest one bit, and store the
         shifted value in hi/lo.  */
      hi = (unsigned long) (hi32.X_add_number & 0xffffffff);
      lo = (unsigned long) (lo32.X_add_number & 0xffffffff);
      if (lo != 0)
       {
         bit = 0;
         while ((lo & 1) == 0)
           {
             lo >>= 1;
             ++bit;
           }
         lo |= (hi & (((unsigned long) 1 << bit) - 1)) << (32 - bit);
         hi >>= bit;
       }
      else
       {
         bit = 32;
         while ((hi & 1) == 0)
           {
             hi >>= 1;
             ++bit;
           }
         lo = hi;
         hi = 0;
       }

      /* Optimize if the shifted value is a (power of 2) - 1.  */
      if ((hi == 0 && ((lo + 1) & lo) == 0)
         || (lo == 0xffffffff && ((hi + 1) & hi) == 0))
       {
         shift = COUNT_TOP_ZEROES ((unsigned int) hi32.X_add_number);
         if (shift != 0)
           {
             expressionS tmp;

             /* This instruction will set the register to be all
                 ones.  */
             tmp.X_op = O_constant;
             tmp.X_add_number = (offsetT) -1;
             macro_build (&tmp, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
             if (bit != 0)
              {
                bit += shift;
                macro_build (NULL, (bit >= 32) ? "dsll32" : "dsll", "d,w,<",
                            reg, reg, (bit >= 32) ? bit - 32 : bit);
              }
             macro_build (NULL, (shift >= 32) ? "dsrl32" : "dsrl", "d,w,<",
                        reg, reg, (shift >= 32) ? shift - 32 : shift);
             return;
           }
       }

      /* Sign extend hi32 before calling load_register, because we can
         generally get better code when we load a sign extended value.  */
      if ((hi32.X_add_number & 0x80000000) != 0)
       hi32.X_add_number |= ~(offsetT) 0xffffffff;
      load_register (reg, &hi32, 0);
      freg = reg;
    }
  if ((lo32.X_add_number & 0xffff0000) == 0)
    {
      if (freg != 0)
       {
         macro_build (NULL, "dsll32", "d,w,<", reg, freg, 0);
         freg = reg;
       }
    }
  else
    {
      expressionS mid16;

      if ((freg == 0) && (lo32.X_add_number == (offsetT) 0xffffffff))
       {
         macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
         macro_build (NULL, "dsrl32", "d,w,<", reg, reg, 0);
         return;
       }

      if (freg != 0)
       {
         macro_build (NULL, "dsll", "d,w,<", reg, freg, 16);
         freg = reg;
       }
      mid16 = lo32;
      mid16.X_add_number >>= 16;
      macro_build (&mid16, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
      macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
      freg = reg;
    }
  if ((lo32.X_add_number & 0xffff) != 0)
    macro_build (&lo32, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void macro ( struct mips_cl_insn ip) [static]

Definition at line 4516 of file tc-mips.c.

{
  int treg, sreg, dreg, breg;
  int tempreg;
  int mask;
  int used_at = 0;
  expressionS expr1;
  const char *s;
  const char *s2;
  const char *fmt;
  int likely = 0;
  int dbl = 0;
  int coproc = 0;
  int lr = 0;
  int imm = 0;
  int call = 0;
  int off;
  offsetT maxnum;
  bfd_reloc_code_real_type r;
  int hold_mips_optimize;

  assert (! mips_opts.mips16);

  treg = (ip->insn_opcode >> 16) & 0x1f;
  dreg = (ip->insn_opcode >> 11) & 0x1f;
  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
  mask = ip->insn_mo->mask;

  expr1.X_op = O_constant;
  expr1.X_op_symbol = NULL;
  expr1.X_add_symbol = NULL;
  expr1.X_add_number = 1;

  switch (mask)
    {
    case M_DABS:
      dbl = 1;
    case M_ABS:
      /* bgez $a0,.+12
        move v0,$a0
        sub v0,$zero,$a0
        */

      start_noreorder ();

      expr1.X_add_number = 8;
      macro_build (&expr1, "bgez", "s,p", sreg);
      if (dreg == sreg)
       macro_build (NULL, "nop", "", 0);
      else
       move_register (dreg, sreg);
      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);

      end_noreorder ();
      break;

    case M_ADD_I:
      s = "addi";
      s2 = "add";
      goto do_addi;
    case M_ADDU_I:
      s = "addiu";
      s2 = "addu";
      goto do_addi;
    case M_DADD_I:
      dbl = 1;
      s = "daddi";
      s2 = "dadd";
      goto do_addi;
    case M_DADDU_I:
      dbl = 1;
      s = "daddiu";
      s2 = "daddu";
    do_addi:
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= -0x8000
         && imm_expr.X_add_number < 0x8000)
       {
         macro_build (&imm_expr, s, "t,r,j", treg, sreg, BFD_RELOC_LO16);
         break;
       }
      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
      break;

    case M_AND_I:
      s = "andi";
      s2 = "and";
      goto do_bit;
    case M_OR_I:
      s = "ori";
      s2 = "or";
      goto do_bit;
    case M_NOR_I:
      s = "";
      s2 = "nor";
      goto do_bit;
    case M_XOR_I:
      s = "xori";
      s2 = "xor";
    do_bit:
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= 0
         && imm_expr.X_add_number < 0x10000)
       {
         if (mask != M_NOR_I)
           macro_build (&imm_expr, s, "t,r,i", treg, sreg, BFD_RELOC_LO16);
         else
           {
             macro_build (&imm_expr, "ori", "t,r,i",
                        treg, sreg, BFD_RELOC_LO16);
             macro_build (NULL, "nor", "d,v,t", treg, treg, 0);
           }
         break;
       }

      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
      break;

    case M_BALIGN:
      switch (imm_expr.X_add_number)
       {
       case 0:
         macro_build (NULL, "nop", "");
         break;
       case 2:
         macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
         break;
       default:
         macro_build (NULL, "balign", "t,s,2", treg, sreg,
                     (int)imm_expr.X_add_number);
         break;
       }
      break;

    case M_BEQ_I:
      s = "beq";
      goto beq_i;
    case M_BEQL_I:
      s = "beql";
      likely = 1;
      goto beq_i;
    case M_BNE_I:
      s = "bne";
      goto beq_i;
    case M_BNEL_I:
      s = "bnel";
      likely = 1;
    beq_i:
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       {
         macro_build (&offset_expr, s, "s,t,p", sreg, 0);
         break;
       }
      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (&offset_expr, s, "s,t,p", sreg, AT);
      break;

    case M_BGEL:
      likely = 1;
    case M_BGE:
      if (treg == 0)
       {
         macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
         break;
       }
      if (sreg == 0)
       {
         macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
      break;

    case M_BGTL_I:
      likely = 1;
    case M_BGT_I:
      /* check for > max integer */
      maxnum = 0x7fffffff;
      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
       {
         maxnum <<= 16;
         maxnum |= 0xffff;
         maxnum <<= 16;
         maxnum |= 0xffff;
       }
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= maxnum
         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
       {
       do_false:
         /* result is always false */
         if (! likely)
           macro_build (NULL, "nop", "", 0);
         else
           macro_build (&offset_expr, "bnel", "s,t,p", 0, 0);
         break;
       }
      if (imm_expr.X_op != O_constant)
       as_bad (_("Unsupported large constant"));
      ++imm_expr.X_add_number;
      /* FALLTHROUGH */
    case M_BGE_I:
    case M_BGEL_I:
      if (mask == M_BGEL_I)
       likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       {
         macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
         break;
       }
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
       {
         macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
         break;
       }
      maxnum = 0x7fffffff;
      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
       {
         maxnum <<= 16;
         maxnum |= 0xffff;
         maxnum <<= 16;
         maxnum |= 0xffff;
       }
      maxnum = - maxnum - 1;
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number <= maxnum
         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
       {
       do_true:
         /* result is always true */
         as_warn (_("Branch %s is always true"), ip->insn_mo->name);
         macro_build (&offset_expr, "b", "p");
         break;
       }
      used_at = 1;
      set_at (sreg, 0);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
      break;

    case M_BGEUL:
      likely = 1;
    case M_BGEU:
      if (treg == 0)
       goto do_true;
      if (sreg == 0)
       {
         macro_build (&offset_expr, likely ? "beql" : "beq",
                     "s,t,p", 0, treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
      break;

    case M_BGTUL_I:
      likely = 1;
    case M_BGTU_I:
      if (sreg == 0
         || (HAVE_32BIT_GPRS
             && imm_expr.X_op == O_constant
             && imm_expr.X_add_number == (offsetT) 0xffffffff))
       goto do_false;
      if (imm_expr.X_op != O_constant)
       as_bad (_("Unsupported large constant"));
      ++imm_expr.X_add_number;
      /* FALLTHROUGH */
    case M_BGEU_I:
    case M_BGEUL_I:
      if (mask == M_BGEUL_I)
       likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       goto do_true;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
       {
         macro_build (&offset_expr, likely ? "bnel" : "bne",
                     "s,t,p", sreg, 0);
         break;
       }
      used_at = 1;
      set_at (sreg, 1);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
      break;

    case M_BGTL:
      likely = 1;
    case M_BGT:
      if (treg == 0)
       {
         macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
         break;
       }
      if (sreg == 0)
       {
         macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
      break;

    case M_BGTUL:
      likely = 1;
    case M_BGTU:
      if (treg == 0)
       {
         macro_build (&offset_expr, likely ? "bnel" : "bne",
                     "s,t,p", sreg, 0);
         break;
       }
      if (sreg == 0)
       goto do_false;
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
      break;

    case M_BLEL:
      likely = 1;
    case M_BLE:
      if (treg == 0)
       {
         macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", sreg);
         break;
       }
      if (sreg == 0)
       {
         macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
      break;

    case M_BLEL_I:
      likely = 1;
    case M_BLE_I:
      maxnum = 0x7fffffff;
      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
       {
         maxnum <<= 16;
         maxnum |= 0xffff;
         maxnum <<= 16;
         maxnum |= 0xffff;
       }
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= maxnum
         && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
       goto do_true;
      if (imm_expr.X_op != O_constant)
       as_bad (_("Unsupported large constant"));
      ++imm_expr.X_add_number;
      /* FALLTHROUGH */
    case M_BLT_I:
    case M_BLTL_I:
      if (mask == M_BLTL_I)
       likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       {
         macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", sreg);
         break;
       }
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
       {
         macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", sreg);
         break;
       }
      used_at = 1;
      set_at (sreg, 0);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
      break;

    case M_BLEUL:
      likely = 1;
    case M_BLEU:
      if (treg == 0)
       {
         macro_build (&offset_expr, likely ? "beql" : "beq",
                     "s,t,p", sreg, 0);
         break;
       }
      if (sreg == 0)
       goto do_true;
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
      break;

    case M_BLEUL_I:
      likely = 1;
    case M_BLEU_I:
      if (sreg == 0
         || (HAVE_32BIT_GPRS
             && imm_expr.X_op == O_constant
             && imm_expr.X_add_number == (offsetT) 0xffffffff))
       goto do_true;
      if (imm_expr.X_op != O_constant)
       as_bad (_("Unsupported large constant"));
      ++imm_expr.X_add_number;
      /* FALLTHROUGH */
    case M_BLTU_I:
    case M_BLTUL_I:
      if (mask == M_BLTUL_I)
       likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       goto do_false;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
       {
         macro_build (&offset_expr, likely ? "beql" : "beq",
                     "s,t,p", sreg, 0);
         break;
       }
      used_at = 1;
      set_at (sreg, 1);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
      break;

    case M_BLTL:
      likely = 1;
    case M_BLT:
      if (treg == 0)
       {
         macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", sreg);
         break;
       }
      if (sreg == 0)
       {
         macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
      break;

    case M_BLTUL:
      likely = 1;
    case M_BLTU:
      if (treg == 0)
       goto do_false;
      if (sreg == 0)
       {
         macro_build (&offset_expr, likely ? "bnel" : "bne",
                     "s,t,p", 0, treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
      break;

    case M_DEXT:
      {
       unsigned long pos;
       unsigned long size;

        if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
         {
           as_bad (_("Unsupported large constant"));
           pos = size = 1;
         }
       else
         {
           pos = (unsigned long) imm_expr.X_add_number;
           size = (unsigned long) imm2_expr.X_add_number;
         }

       if (pos > 63)
         {
           as_bad (_("Improper position (%lu)"), pos);
           pos = 1;
         }
        if (size == 0 || size > 64
           || (pos + size - 1) > 63)
         {
           as_bad (_("Improper extract size (%lu, position %lu)"),
                  size, pos);
           size = 1;
         }

       if (size <= 32 && pos < 32)
         {
           s = "dext";
           fmt = "t,r,+A,+C";
         }
       else if (size <= 32)
         {
           s = "dextu";
           fmt = "t,r,+E,+H";
         }
       else
         {
           s = "dextm";
           fmt = "t,r,+A,+G";
         }
       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos, size - 1);
      }
      break;

    case M_DINS:
      {
       unsigned long pos;
       unsigned long size;

        if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
         {
           as_bad (_("Unsupported large constant"));
           pos = size = 1;
         }
       else
         {
           pos = (unsigned long) imm_expr.X_add_number;
           size = (unsigned long) imm2_expr.X_add_number;
         }

       if (pos > 63)
         {
           as_bad (_("Improper position (%lu)"), pos);
           pos = 1;
         }
        if (size == 0 || size > 64
           || (pos + size - 1) > 63)
         {
           as_bad (_("Improper insert size (%lu, position %lu)"),
                  size, pos);
           size = 1;
         }

       if (pos < 32 && (pos + size - 1) < 32)
         {
           s = "dins";
           fmt = "t,r,+A,+B";
         }
       else if (pos >= 32)
         {
           s = "dinsu";
           fmt = "t,r,+E,+F";
         }
       else
         {
           s = "dinsm";
           fmt = "t,r,+A,+F";
         }
       macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos,
                   pos + size - 1);
      }
      break;

    case M_DDIV_3:
      dbl = 1;
    case M_DIV_3:
      s = "mflo";
      goto do_div3;
    case M_DREM_3:
      dbl = 1;
    case M_REM_3:
      s = "mfhi";
    do_div3:
      if (treg == 0)
       {
         as_warn (_("Divide by zero."));
         if (mips_trap)
           macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
         else
           macro_build (NULL, "break", "c", 7);
         break;
       }

      start_noreorder ();
      if (mips_trap)
       {
         macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
       }
      else
       {
         expr1.X_add_number = 8;
         macro_build (&expr1, "bne", "s,t,p", treg, 0);
         macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
         macro_build (NULL, "break", "c", 7);
       }
      expr1.X_add_number = -1;
      used_at = 1;
      load_register (AT, &expr1, dbl);
      expr1.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
      macro_build (&expr1, "bne", "s,t,p", treg, AT);
      if (dbl)
       {
         expr1.X_add_number = 1;
         load_register (AT, &expr1, dbl);
         macro_build (NULL, "dsll32", "d,w,<", AT, AT, 31);
       }
      else
       {
         expr1.X_add_number = 0x80000000;
         macro_build (&expr1, "lui", "t,u", AT, BFD_RELOC_HI16);
       }
      if (mips_trap)
       {
         macro_build (NULL, "teq", "s,t,q", sreg, AT, 6);
         /* We want to close the noreorder block as soon as possible, so
            that later insns are available for delay slot filling.  */
         end_noreorder ();
       }
      else
       {
         expr1.X_add_number = 8;
         macro_build (&expr1, "bne", "s,t,p", sreg, AT);
         macro_build (NULL, "nop", "", 0);

         /* We want to close the noreorder block as soon as possible, so
            that later insns are available for delay slot filling.  */
         end_noreorder ();

         macro_build (NULL, "break", "c", 6);
       }
      macro_build (NULL, s, "d", dreg);
      break;

    case M_DIV_3I:
      s = "div";
      s2 = "mflo";
      goto do_divi;
    case M_DIVU_3I:
      s = "divu";
      s2 = "mflo";
      goto do_divi;
    case M_REM_3I:
      s = "div";
      s2 = "mfhi";
      goto do_divi;
    case M_REMU_3I:
      s = "divu";
      s2 = "mfhi";
      goto do_divi;
    case M_DDIV_3I:
      dbl = 1;
      s = "ddiv";
      s2 = "mflo";
      goto do_divi;
    case M_DDIVU_3I:
      dbl = 1;
      s = "ddivu";
      s2 = "mflo";
      goto do_divi;
    case M_DREM_3I:
      dbl = 1;
      s = "ddiv";
      s2 = "mfhi";
      goto do_divi;
    case M_DREMU_3I:
      dbl = 1;
      s = "ddivu";
      s2 = "mfhi";
    do_divi:
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       {
         as_warn (_("Divide by zero."));
         if (mips_trap)
           macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
         else
           macro_build (NULL, "break", "c", 7);
         break;
       }
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
       {
         if (strcmp (s2, "mflo") == 0)
           move_register (dreg, sreg);
         else
           move_register (dreg, 0);
         break;
       }
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number == -1
         && s[strlen (s) - 1] != 'u')
       {
         if (strcmp (s2, "mflo") == 0)
           {
             macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
           }
         else
           move_register (dreg, 0);
         break;
       }

      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, s, "z,s,t", sreg, AT);
      macro_build (NULL, s2, "d", dreg);
      break;

    case M_DIVU_3:
      s = "divu";
      s2 = "mflo";
      goto do_divu3;
    case M_REMU_3:
      s = "divu";
      s2 = "mfhi";
      goto do_divu3;
    case M_DDIVU_3:
      s = "ddivu";
      s2 = "mflo";
      goto do_divu3;
    case M_DREMU_3:
      s = "ddivu";
      s2 = "mfhi";
    do_divu3:
      start_noreorder ();
      if (mips_trap)
       {
         macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
         macro_build (NULL, s, "z,s,t", sreg, treg);
         /* We want to close the noreorder block as soon as possible, so
            that later insns are available for delay slot filling.  */
         end_noreorder ();
       }
      else
       {
         expr1.X_add_number = 8;
         macro_build (&expr1, "bne", "s,t,p", treg, 0);
         macro_build (NULL, s, "z,s,t", sreg, treg);

         /* We want to close the noreorder block as soon as possible, so
            that later insns are available for delay slot filling.  */
         end_noreorder ();
         macro_build (NULL, "break", "c", 7);
       }
      macro_build (NULL, s2, "d", dreg);
      break;

    case M_DLCA_AB:
      dbl = 1;
    case M_LCA_AB:
      call = 1;
      goto do_la;
    case M_DLA_AB:
      dbl = 1;
    case M_LA_AB:
    do_la:
      /* Load the address of a symbol into a register.  If breg is not
        zero, we then add a base register to it.  */

      if (dbl && HAVE_32BIT_GPRS)
       as_warn (_("dla used to load 32-bit register"));

      if (! dbl && HAVE_64BIT_OBJECTS)
       as_warn (_("la used to load 64-bit address"));

      if (offset_expr.X_op == O_constant
         && offset_expr.X_add_number >= -0x8000
         && offset_expr.X_add_number < 0x8000)
       {
         macro_build (&offset_expr, ADDRESS_ADDI_INSN,
                     "t,r,j", treg, sreg, BFD_RELOC_LO16);
         break;
       }

      if (!mips_opts.noat && (treg == breg))
       {
         tempreg = AT;
         used_at = 1;
       }
      else
       {
         tempreg = treg;
       }

      if (offset_expr.X_op != O_symbol
         && offset_expr.X_op != O_constant)
       {
         as_bad (_("expression too complex"));
         offset_expr.X_op = O_constant;
       }

      if (offset_expr.X_op == O_constant)
       load_register (tempreg, &offset_expr, HAVE_64BIT_ADDRESSES);
      else if (mips_pic == NO_PIC)
       {
         /* If this is a reference to a GP relative symbol, we want
              addiu  $tempreg,$gp,<sym>   (BFD_RELOC_GPREL16)
            Otherwise we want
              lui    $tempreg,<sym>              (BFD_RELOC_HI16_S)
              addiu  $tempreg,$tempreg,<sym>     (BFD_RELOC_LO16)
            If we have a constant, we need two instructions anyhow,
            so we may as well always use the latter form.

            With 64bit address space and a usable $at we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
              lui    $at,<sym>            (BFD_RELOC_HI16_S)
              daddiu $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHER)
              daddiu $at,<sym>            (BFD_RELOC_LO16)
              dsll32 $tempreg,0
              daddu  $tempreg,$tempreg,$at

            If $at is already in use, we use a path which is suboptimal
            on superscalar processors.
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
              daddiu $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHER)
              dsll   $tempreg,16
              daddiu $tempreg,<sym>              (BFD_RELOC_HI16_S)
              dsll   $tempreg,16
              daddiu $tempreg,<sym>              (BFD_RELOC_LO16)

            For GP relative symbols in 64bit address space we can use
            the same sequence as in 32bit address space.  */
         if (HAVE_64BIT_SYMBOLS)
           {
             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
                && !nopic_need_relax (offset_expr.X_add_symbol, 1))
              {
                relax_start (offset_expr.X_add_symbol);
                macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                            tempreg, mips_gp_register, BFD_RELOC_GPREL16);
                relax_switch ();
              }

             if (used_at == 0 && !mips_opts.noat)
              {
                macro_build (&offset_expr, "lui", "t,u",
                            tempreg, BFD_RELOC_MIPS_HIGHEST);
                macro_build (&offset_expr, "lui", "t,u",
                            AT, BFD_RELOC_HI16_S);
                macro_build (&offset_expr, "daddiu", "t,r,j",
                            tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
                macro_build (&offset_expr, "daddiu", "t,r,j",
                            AT, AT, BFD_RELOC_LO16);
                macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
                macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                used_at = 1;
              }
             else
              {
                macro_build (&offset_expr, "lui", "t,u",
                            tempreg, BFD_RELOC_MIPS_HIGHEST);
                macro_build (&offset_expr, "daddiu", "t,r,j",
                            tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
                macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                macro_build (&offset_expr, "daddiu", "t,r,j",
                            tempreg, tempreg, BFD_RELOC_HI16_S);
                macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                macro_build (&offset_expr, "daddiu", "t,r,j",
                            tempreg, tempreg, BFD_RELOC_LO16);
              }

             if (mips_relax.sequence)
              relax_end ();
           }
         else
           {
             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
                && !nopic_need_relax (offset_expr.X_add_symbol, 1))
              {
                relax_start (offset_expr.X_add_symbol);
                macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                            tempreg, mips_gp_register, BFD_RELOC_GPREL16);
                relax_switch ();
              }
             if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
              as_bad (_("offset too large"));
             macro_build_lui (&offset_expr, tempreg);
             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                        tempreg, tempreg, BFD_RELOC_LO16);
             if (mips_relax.sequence)
              relax_end ();
           }
       }
      else if (!mips_big_got && !HAVE_NEWABI)
       {
         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;

         /* If this is a reference to an external symbol, and there
            is no constant, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
            or for lca or if tempreg is PIC_CALL_REG
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_CALL16)
            For a local symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $tempreg,$tempreg,<sym>     (BFD_RELOC_LO16)

            If we have a small constant, and this is a reference to
            an external symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $tempreg,$tempreg,<constant>
            For a local symbol, we want the same instruction
            sequence, but we output a BFD_RELOC_LO16 reloc on the
            addiu instruction.

            If we have a large constant, and this is a reference to
            an external symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              lui    $at,<hiconstant>
              addiu  $at,$at,<loconstant>
              addu   $tempreg,$tempreg,$at
            For a local symbol, we want the same instruction
            sequence, but we output a BFD_RELOC_LO16 reloc on the
            addiu instruction.
          */

         if (offset_expr.X_add_number == 0)
           {
             if (mips_pic == SVR4_PIC
                && breg == 0
                && (call || tempreg == PIC_CALL_REG))
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;

             relax_start (offset_expr.X_add_symbol);
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        lw_reloc_type, mips_gp_register);
             if (breg != 0)
              {
                /* We're going to put in an addu instruction using
                   tempreg, so we may as well insert the nop right
                   now.  */
                load_delay_nop ();
              }
             relax_switch ();
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                        tempreg, BFD_RELOC_MIPS_GOT16, mips_gp_register);
             load_delay_nop ();
             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                        tempreg, tempreg, BFD_RELOC_LO16);
             relax_end ();
             /* FIXME: If breg == 0, and the next instruction uses
               $tempreg, then if this variant case is used an extra
               nop will be generated.  */
           }
         else if (offset_expr.X_add_number >= -0x8000
                 && offset_expr.X_add_number < 0x8000)
           {
             load_got_offset (tempreg, &offset_expr);
             load_delay_nop ();
             add_got_offset (tempreg, &offset_expr);
           }
         else
           {
             expr1.X_add_number = offset_expr.X_add_number;
             offset_expr.X_add_number =
              ((offset_expr.X_add_number + 0x8000) & 0xffff) - 0x8000;
             load_got_offset (tempreg, &offset_expr);
             offset_expr.X_add_number = expr1.X_add_number;
             /* If we are going to add in a base register, and the
               target register and the base register are the same,
               then we are using AT as a temporary register.  Since
               we want to load the constant into AT, we add our
               current AT (from the global offset table) and the
               register into the register now, and pretend we were
               not using a base register.  */
             if (breg == treg)
              {
                load_delay_nop ();
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            treg, AT, breg);
                breg = 0;
                tempreg = treg;
              }
             add_got_offset_hilo (tempreg, &offset_expr, AT);
             used_at = 1;
           }
       }
      else if (!mips_big_got && HAVE_NEWABI)
       {
         int add_breg_early = 0;

         /* If this is a reference to an external, and there is no
            constant, or local symbol (*), with or without a
            constant, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT_DISP)
            or for lca or if tempreg is PIC_CALL_REG
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_CALL16)

            If we have a small constant, and this is a reference to
            an external symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT_DISP)
              addiu  $tempreg,$tempreg,<constant>

            If we have a large constant, and this is a reference to
            an external symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT_DISP)
              lui    $at,<hiconstant>
              addiu  $at,$at,<loconstant>
              addu   $tempreg,$tempreg,$at

            (*) Other assemblers seem to prefer GOT_PAGE/GOT_OFST for
            local symbols, even though it introduces an additional
            instruction.  */

         if (offset_expr.X_add_number)
           {
             expr1.X_add_number = offset_expr.X_add_number;
             offset_expr.X_add_number = 0;

             relax_start (offset_expr.X_add_symbol);
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);

             if (expr1.X_add_number >= -0x8000
                && expr1.X_add_number < 0x8000)
              {
                macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
                            tempreg, tempreg, BFD_RELOC_LO16);
              }
             else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
              {
                int dreg;

                /* If we are going to add in a base register, and the
                   target register and the base register are the same,
                   then we are using AT as a temporary register.  Since
                   we want to load the constant into AT, we add our
                   current AT (from the global offset table) and the
                   register into the register now, and pretend we were
                   not using a base register.  */
                if (breg != treg)
                  dreg = tempreg;
                else
                  {
                    assert (tempreg == AT);
                    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               treg, AT, breg);
                    dreg = treg;
                    add_breg_early = 1;
                  }

                load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            dreg, dreg, AT);

                used_at = 1;
              }
             else
              as_bad (_("PIC code offset overflow (max 32 signed bits)"));

             relax_switch ();
             offset_expr.X_add_number = expr1.X_add_number;

             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
             if (add_breg_early)
              {
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            treg, tempreg, breg);
                breg = 0;
                tempreg = treg;
              }
             relax_end ();
           }
         else if (breg == 0 && (call || tempreg == PIC_CALL_REG))
           {
             relax_start (offset_expr.X_add_symbol);
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        BFD_RELOC_MIPS_CALL16, mips_gp_register);
             relax_switch ();
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
             relax_end ();
           }
         else
           {
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
           }
       }
      else if (mips_big_got && !HAVE_NEWABI)
       {
         int gpdelay;
         int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
         int local_reloc_type = (int) BFD_RELOC_MIPS_GOT16;

         /* This is the large GOT case.  If this is a reference to an
            external symbol, and there is no constant, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              addu   $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
            or for lca or if tempreg is PIC_CALL_REG
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_CALL_HI16)
              addu   $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
            For a local symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $tempreg,$tempreg,<sym>     (BFD_RELOC_LO16)

            If we have a small constant, and this is a reference to
            an external symbol, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              addu   $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
              nop
              addiu  $tempreg,$tempreg,<constant>
            For a local symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $tempreg,$tempreg,<constant> (BFD_RELOC_LO16)

            If we have a large constant, and this is a reference to
            an external symbol, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              addu   $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
              lui    $at,<hiconstant>
              addiu  $at,$at,<loconstant>
              addu   $tempreg,$tempreg,$at
            For a local symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              lui    $at,<hiconstant>
              addiu  $at,$at,<loconstant> (BFD_RELOC_LO16)
              addu   $tempreg,$tempreg,$at
         */

         expr1.X_add_number = offset_expr.X_add_number;
         offset_expr.X_add_number = 0;
         relax_start (offset_expr.X_add_symbol);
         gpdelay = reg_needs_delay (mips_gp_register);
         if (expr1.X_add_number == 0 && breg == 0
             && (call || tempreg == PIC_CALL_REG))
           {
             lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
             lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
           }
         macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                     tempreg, tempreg, mips_gp_register);
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                     tempreg, lw_reloc_type, tempreg);
         if (expr1.X_add_number == 0)
           {
             if (breg != 0)
              {
                /* We're going to put in an addu instruction using
                   tempreg, so we may as well insert the nop right
                   now.  */
                load_delay_nop ();
              }
           }
         else if (expr1.X_add_number >= -0x8000
                 && expr1.X_add_number < 0x8000)
           {
             load_delay_nop ();
             macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
                        tempreg, tempreg, BFD_RELOC_LO16);
           }
         else
           {
             int dreg;

             /* If we are going to add in a base register, and the
               target register and the base register are the same,
               then we are using AT as a temporary register.  Since
               we want to load the constant into AT, we add our
               current AT (from the global offset table) and the
               register into the register now, and pretend we were
               not using a base register.  */
             if (breg != treg)
              dreg = tempreg;
             else
              {
                assert (tempreg == AT);
                load_delay_nop ();
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            treg, AT, breg);
                dreg = treg;
              }

             load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);

             used_at = 1;
           }
         offset_expr.X_add_number =
           ((expr1.X_add_number + 0x8000) & 0xffff) - 0x8000;
         relax_switch ();

         if (gpdelay)
           {
             /* This is needed because this instruction uses $gp, but
               the first instruction on the main stream does not.  */
             macro_build (NULL, "nop", "");
           }

         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     local_reloc_type, mips_gp_register);
         if (expr1.X_add_number >= -0x8000
             && expr1.X_add_number < 0x8000)
           {
             load_delay_nop ();
             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                        tempreg, tempreg, BFD_RELOC_LO16);
             /* FIXME: If add_number is 0, and there was no base
               register, the external symbol case ended with a load,
               so if the symbol turns out to not be external, and
               the next instruction uses tempreg, an unnecessary nop
               will be inserted.  */
           }
         else
           {
             if (breg == treg)
              {
                /* We must add in the base register now, as in the
                   external symbol case.  */
                assert (tempreg == AT);
                load_delay_nop ();
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            treg, AT, breg);
                tempreg = treg;
                /* We set breg to 0 because we have arranged to add
                   it in in both cases.  */
                breg = 0;
              }

             macro_build_lui (&expr1, AT);
             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                        AT, AT, BFD_RELOC_LO16);
             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                        tempreg, tempreg, AT);
             used_at = 1;
           }
         relax_end ();
       }
      else if (mips_big_got && HAVE_NEWABI)
       {
         int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
         int add_breg_early = 0;

         /* This is the large GOT case.  If this is a reference to an
            external symbol, and there is no constant, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              add    $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
            or for lca or if tempreg is PIC_CALL_REG
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_CALL_HI16)
              add    $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)

            If we have a small constant, and this is a reference to
            an external symbol, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              add    $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
              addi   $tempreg,$tempreg,<constant>

            If we have a large constant, and this is a reference to
            an external symbol, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              addu   $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
              lui    $at,<hiconstant>
              addi   $at,$at,<loconstant>
              add    $tempreg,$tempreg,$at

            If we have NewABI, and we know it's a local symbol, we want
              lw     $reg,<sym>($gp)             (BFD_RELOC_MIPS_GOT_PAGE)
              addiu  $reg,$reg,<sym>             (BFD_RELOC_MIPS_GOT_OFST)
            otherwise we have to resort to GOT_HI16/GOT_LO16.  */

         relax_start (offset_expr.X_add_symbol);

         expr1.X_add_number = offset_expr.X_add_number;
         offset_expr.X_add_number = 0;

         if (expr1.X_add_number == 0 && breg == 0
             && (call || tempreg == PIC_CALL_REG))
           {
             lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
             lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
           }
         macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                     tempreg, tempreg, mips_gp_register);
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                     tempreg, lw_reloc_type, tempreg);

         if (expr1.X_add_number == 0)
           ;
         else if (expr1.X_add_number >= -0x8000
                 && expr1.X_add_number < 0x8000)
           {
             macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
                        tempreg, tempreg, BFD_RELOC_LO16);
           }
         else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
           {
             int dreg;

             /* If we are going to add in a base register, and the
               target register and the base register are the same,
               then we are using AT as a temporary register.  Since
               we want to load the constant into AT, we add our
               current AT (from the global offset table) and the
               register into the register now, and pretend we were
               not using a base register.  */
             if (breg != treg)
              dreg = tempreg;
             else
              {
                assert (tempreg == AT);
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            treg, AT, breg);
                dreg = treg;
                add_breg_early = 1;
              }

             load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);

             used_at = 1;
           }
         else
           as_bad (_("PIC code offset overflow (max 32 signed bits)"));

         relax_switch ();
         offset_expr.X_add_number = expr1.X_add_number;
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
                     tempreg, BFD_RELOC_MIPS_GOT_OFST);
         if (add_breg_early)
           {
             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                        treg, tempreg, breg);
             breg = 0;
             tempreg = treg;
           }
         relax_end ();
       }
      else
       abort ();

      if (breg != 0)
       macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
      break;

    case M_J_A:
      /* The j instruction may not be used in PIC code, since it
        requires an absolute address.  We convert it to a b
        instruction.  */
      if (mips_pic == NO_PIC)
       macro_build (&offset_expr, "j", "a");
      else
       macro_build (&offset_expr, "b", "p");
      break;

      /* The jal instructions must be handled as macros because when
        generating PIC code they expand to multi-instruction
        sequences.  Normally they are simple instructions.  */
    case M_JAL_1:
      dreg = RA;
      /* Fall through.  */
    case M_JAL_2:
      if (mips_pic == NO_PIC)
       macro_build (NULL, "jalr", "d,s", dreg, sreg);
      else
       {
         if (sreg != PIC_CALL_REG)
           as_warn (_("MIPS PIC call to register other than $25"));

         macro_build (NULL, "jalr", "d,s", dreg, sreg);
         if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
           {
             if (mips_cprestore_offset < 0)
              as_warn (_("No .cprestore pseudo-op used in PIC code"));
             else
              {
                if (! mips_frame_reg_valid)
                  {
                    as_warn (_("No .frame pseudo-op used in PIC code"));
                    /* Quiet this warning.  */
                    mips_frame_reg_valid = 1;
                  }
                if (! mips_cprestore_valid)
                  {
                    as_warn (_("No .cprestore pseudo-op used in PIC code"));
                    /* Quiet this warning.  */
                    mips_cprestore_valid = 1;
                  }
                expr1.X_add_number = mips_cprestore_offset;
                macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
                                          mips_gp_register,
                                          mips_frame_reg,
                                          HAVE_64BIT_ADDRESSES);
              }
           }
       }

      break;

    case M_JAL_A:
      if (mips_pic == NO_PIC)
       macro_build (&offset_expr, "jal", "a");
      else if (mips_pic == SVR4_PIC)
       {
         /* If this is a reference to an external symbol, and we are
            using a small GOT, we want
              lw     $25,<sym>($gp)              (BFD_RELOC_MIPS_CALL16)
              nop
              jalr   $ra,$25
              nop
              lw     $gp,cprestore($sp)
            The cprestore value is set using the .cprestore
            pseudo-op.  If we are using a big GOT, we want
              lui    $25,<sym>            (BFD_RELOC_MIPS_CALL_HI16)
              addu   $25,$25,$gp
              lw     $25,<sym>($25)              (BFD_RELOC_MIPS_CALL_LO16)
              nop
              jalr   $ra,$25
              nop
              lw     $gp,cprestore($sp)
            If the symbol is not external, we want
              lw     $25,<sym>($gp)              (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $25,$25,<sym>        (BFD_RELOC_LO16)
              jalr   $ra,$25
              nop
              lw $gp,cprestore($sp)

            For NewABI, we use the same CALL16 or CALL_HI16/CALL_LO16
            sequences above, minus nops, unless the symbol is local,
            which enables us to use GOT_PAGE/GOT_OFST (big got) or
            GOT_DISP.  */
         if (HAVE_NEWABI)
           {
             if (! mips_big_got)
              {
                relax_start (offset_expr.X_add_symbol);
                macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                            PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
                            mips_gp_register);
                relax_switch ();
                macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                            PIC_CALL_REG, BFD_RELOC_MIPS_GOT_DISP,
                            mips_gp_register);
                relax_end ();
              }
             else
              {
                relax_start (offset_expr.X_add_symbol);
                macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
                            BFD_RELOC_MIPS_CALL_HI16);
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
                            PIC_CALL_REG, mips_gp_register);
                macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                            PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
                            PIC_CALL_REG);
                relax_switch ();
                macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                            PIC_CALL_REG, BFD_RELOC_MIPS_GOT_PAGE,
                            mips_gp_register);
                macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                            PIC_CALL_REG, PIC_CALL_REG,
                            BFD_RELOC_MIPS_GOT_OFST);
                relax_end ();
              }

             macro_build_jalr (&offset_expr);
           }
         else
           {
             relax_start (offset_expr.X_add_symbol);
             if (! mips_big_got)
              {
                macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                            PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
                            mips_gp_register);
                load_delay_nop ();
                relax_switch ();
              }
             else
              {
                int gpdelay;

                gpdelay = reg_needs_delay (mips_gp_register);
                macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
                            BFD_RELOC_MIPS_CALL_HI16);
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
                            PIC_CALL_REG, mips_gp_register);
                macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                            PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
                            PIC_CALL_REG);
                load_delay_nop ();
                relax_switch ();
                if (gpdelay)
                  macro_build (NULL, "nop", "");
              }
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                        PIC_CALL_REG, BFD_RELOC_MIPS_GOT16,
                        mips_gp_register);
             load_delay_nop ();
             macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                        PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
             relax_end ();
             macro_build_jalr (&offset_expr);

             if (mips_cprestore_offset < 0)
              as_warn (_("No .cprestore pseudo-op used in PIC code"));
             else
              {
                if (! mips_frame_reg_valid)
                  {
                    as_warn (_("No .frame pseudo-op used in PIC code"));
                    /* Quiet this warning.  */
                    mips_frame_reg_valid = 1;
                  }
                if (! mips_cprestore_valid)
                  {
                    as_warn (_("No .cprestore pseudo-op used in PIC code"));
                    /* 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,
                                          mips_frame_reg,
                                          HAVE_64BIT_ADDRESSES);
              }
           }
       }
      else if (mips_pic == VXWORKS_PIC)
       as_bad (_("Non-PIC jump used in PIC library"));
      else
       abort ();

      break;

    case M_LB_AB:
      s = "lb";
      goto ld;
    case M_LBU_AB:
      s = "lbu";
      goto ld;
    case M_LH_AB:
      s = "lh";
      goto ld;
    case M_LHU_AB:
      s = "lhu";
      goto ld;
    case M_LW_AB:
      s = "lw";
      goto ld;
    case M_LWC0_AB:
      s = "lwc0";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LWC1_AB:
      s = "lwc1";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LWC2_AB:
      s = "lwc2";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LWC3_AB:
      s = "lwc3";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LWL_AB:
      s = "lwl";
      lr = 1;
      goto ld;
    case M_LWR_AB:
      s = "lwr";
      lr = 1;
      goto ld;
    case M_LDC1_AB:
      if (mips_opts.arch == CPU_R4650)
       {
         as_bad (_("opcode not supported on this processor"));
         break;
       }
      s = "ldc1";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LDC2_AB:
      s = "ldc2";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LDC3_AB:
      s = "ldc3";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ld;
    case M_LDL_AB:
      s = "ldl";
      lr = 1;
      goto ld;
    case M_LDR_AB:
      s = "ldr";
      lr = 1;
      goto ld;
    case M_LL_AB:
      s = "ll";
      goto ld;
    case M_LLD_AB:
      s = "lld";
      goto ld;
    case M_LWU_AB:
      s = "lwu";
    ld:
      if (breg == treg || coproc || lr)
       {
         tempreg = AT;
         used_at = 1;
       }
      else
       {
         tempreg = treg;
       }
      goto ld_st;
    case M_SB_AB:
      s = "sb";
      goto st;
    case M_SH_AB:
      s = "sh";
      goto st;
    case M_SW_AB:
      s = "sw";
      goto st;
    case M_SWC0_AB:
      s = "swc0";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto st;
    case M_SWC1_AB:
      s = "swc1";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto st;
    case M_SWC2_AB:
      s = "swc2";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto st;
    case M_SWC3_AB:
      s = "swc3";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto st;
    case M_SWL_AB:
      s = "swl";
      goto st;
    case M_SWR_AB:
      s = "swr";
      goto st;
    case M_SC_AB:
      s = "sc";
      goto st;
    case M_SCD_AB:
      s = "scd";
      goto st;
    case M_CACHE_AB:
      s = "cache";
      goto st;
    case M_SDC1_AB:
      if (mips_opts.arch == CPU_R4650)
       {
         as_bad (_("opcode not supported on this processor"));
         break;
       }
      s = "sdc1";
      coproc = 1;
      /* Itbl support may require additional care here.  */
      goto st;
    case M_SDC2_AB:
      s = "sdc2";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto st;
    case M_SDC3_AB:
      s = "sdc3";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto st;
    case M_SDL_AB:
      s = "sdl";
      goto st;
    case M_SDR_AB:
      s = "sdr";
    st:
      tempreg = AT;
      used_at = 1;
    ld_st:
      /* Itbl support may require additional care here.  */
      if (mask == M_LWC1_AB
         || mask == M_SWC1_AB
         || mask == M_LDC1_AB
         || mask == M_SDC1_AB
         || mask == M_L_DAB
         || mask == M_S_DAB)
       fmt = "T,o(b)";
      else if (mask == M_CACHE_AB)
       fmt = "k,o(b)";
      else if (coproc)
       fmt = "E,o(b)";
      else
       fmt = "t,o(b)";

      if (offset_expr.X_op != O_constant
         && offset_expr.X_op != O_symbol)
       {
         as_bad (_("expression too complex"));
         offset_expr.X_op = O_constant;
       }

      if (HAVE_32BIT_ADDRESSES
         && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
       {
         char value [32];

         sprintf_vma (value, offset_expr.X_add_number);
         as_bad (_("Number (0x%s) larger than 32 bits"), value);
       }

      /* A constant expression in PIC code can be handled just as it
        is in non PIC code.  */
      if (offset_expr.X_op == O_constant)
       {
         expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
                            & ~(bfd_vma) 0xffff);
         normalize_address_expr (&expr1);
         load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                      tempreg, tempreg, breg);
         macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
       }
      else if (mips_pic == NO_PIC)
       {
         /* If this is a reference to a GP relative symbol, and there
            is no base register, we want
              <op>   $treg,<sym>($gp)     (BFD_RELOC_GPREL16)
            Otherwise, if there is no base register, we want
              lui    $tempreg,<sym>              (BFD_RELOC_HI16_S)
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_LO16)
            If we have a constant, we need two instructions anyhow,
            so we always use the latter form.

            If we have a base register, and this is a reference to a
            GP relative symbol, we want
              addu   $tempreg,$breg,$gp
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_GPREL16)
            Otherwise we want
              lui    $tempreg,<sym>              (BFD_RELOC_HI16_S)
              addu   $tempreg,$tempreg,$breg
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_LO16)
            With a constant we always use the latter case.

            With 64bit address space and no base register and $at usable,
            we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
              lui    $at,<sym>            (BFD_RELOC_HI16_S)
              daddiu $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHER)
              dsll32 $tempreg,0
              daddu  $tempreg,$at
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_LO16)
            If we have a base register, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
              lui    $at,<sym>            (BFD_RELOC_HI16_S)
              daddiu $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHER)
              daddu  $at,$breg
              dsll32 $tempreg,0
              daddu  $tempreg,$at
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_LO16)

            Without $at we can't generate the optimal path for superscalar
            processors here since this would require two temporary registers.
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
              daddiu $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHER)
              dsll   $tempreg,16
              daddiu $tempreg,<sym>              (BFD_RELOC_HI16_S)
              dsll   $tempreg,16
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_LO16)
            If we have a base register, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHEST)
              daddiu $tempreg,<sym>              (BFD_RELOC_MIPS_HIGHER)
              dsll   $tempreg,16
              daddiu $tempreg,<sym>              (BFD_RELOC_HI16_S)
              dsll   $tempreg,16
              daddu  $tempreg,$tempreg,$breg
              <op>   $treg,<sym>($tempreg)       (BFD_RELOC_LO16)

            For GP relative symbols in 64bit address space we can use
            the same sequence as in 32bit address space.  */
         if (HAVE_64BIT_SYMBOLS)
           {
             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
                && !nopic_need_relax (offset_expr.X_add_symbol, 1))
              {
                relax_start (offset_expr.X_add_symbol);
                if (breg == 0)
                  {
                    macro_build (&offset_expr, s, fmt, treg,
                               BFD_RELOC_GPREL16, mips_gp_register);
                  }
                else
                  {
                    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                               tempreg, breg, mips_gp_register);
                    macro_build (&offset_expr, s, fmt, treg,
                               BFD_RELOC_GPREL16, tempreg);
                  }
                relax_switch ();
              }

             if (used_at == 0 && !mips_opts.noat)
              {
                macro_build (&offset_expr, "lui", "t,u", tempreg,
                            BFD_RELOC_MIPS_HIGHEST);
                macro_build (&offset_expr, "lui", "t,u", AT,
                            BFD_RELOC_HI16_S);
                macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                            tempreg, BFD_RELOC_MIPS_HIGHER);
                if (breg != 0)
                  macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
                macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
                macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
                            tempreg);
                used_at = 1;
              }
             else
              {
                macro_build (&offset_expr, "lui", "t,u", tempreg,
                            BFD_RELOC_MIPS_HIGHEST);
                macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                            tempreg, BFD_RELOC_MIPS_HIGHER);
                macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                            tempreg, BFD_RELOC_HI16_S);
                macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                if (breg != 0)
                  macro_build (NULL, "daddu", "d,v,t",
                             tempreg, tempreg, breg);
                macro_build (&offset_expr, s, fmt, treg,
                            BFD_RELOC_LO16, tempreg);
              }

             if (mips_relax.sequence)
              relax_end ();
             break;
           }

         if (breg == 0)
           {
             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
                && !nopic_need_relax (offset_expr.X_add_symbol, 1))
              {
                relax_start (offset_expr.X_add_symbol);
                macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_GPREL16,
                            mips_gp_register);
                relax_switch ();
              }
             macro_build_lui (&offset_expr, tempreg);
             macro_build (&offset_expr, s, fmt, treg,
                        BFD_RELOC_LO16, tempreg);
             if (mips_relax.sequence)
              relax_end ();
           }
         else
           {
             if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
                && !nopic_need_relax (offset_expr.X_add_symbol, 1))
              {
                relax_start (offset_expr.X_add_symbol);
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            tempreg, breg, mips_gp_register);
                macro_build (&offset_expr, s, fmt, treg,
                            BFD_RELOC_GPREL16, tempreg);
                relax_switch ();
              }
             macro_build_lui (&offset_expr, tempreg);
             macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                        tempreg, tempreg, breg);
             macro_build (&offset_expr, s, fmt, treg,
                        BFD_RELOC_LO16, tempreg);
             if (mips_relax.sequence)
              relax_end ();
           }
       }
      else if (!mips_big_got)
       {
         int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;

         /* If this is a reference to an external symbol, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              <op>   $treg,0($tempreg)
            Otherwise we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $tempreg,$tempreg,<sym>     (BFD_RELOC_LO16)
              <op>   $treg,0($tempreg)

            For NewABI, we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT_PAGE)
              <op>   $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)

            If there is a base register, we add it to $tempreg before
            the <op>.  If there is a constant, we stick it in the
            <op> instruction.  We don't handle constants larger than
            16 bits, because we have no way to load the upper 16 bits
            (actually, we could handle them for the subset of cases
            in which we are not using $at).  */
         assert (offset_expr.X_op == O_symbol);
         if (HAVE_NEWABI)
           {
             macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                        BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
             if (breg != 0)
              macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                          tempreg, tempreg, breg);
             macro_build (&offset_expr, s, fmt, treg,
                        BFD_RELOC_MIPS_GOT_OFST, tempreg);
             break;
           }
         expr1.X_add_number = offset_expr.X_add_number;
         offset_expr.X_add_number = 0;
         if (expr1.X_add_number < -0x8000
             || expr1.X_add_number >= 0x8000)
           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     lw_reloc_type, mips_gp_register);
         load_delay_nop ();
         relax_start (offset_expr.X_add_symbol);
         relax_switch ();
         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
                     tempreg, BFD_RELOC_LO16);
         relax_end ();
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                      tempreg, tempreg, breg);
         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
       }
      else if (mips_big_got && !HAVE_NEWABI)
       {
         int gpdelay;

         /* If this is a reference to an external symbol, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              addu   $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
              <op>   $treg,0($tempreg)
            Otherwise we want
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT16)
              nop
              addiu  $tempreg,$tempreg,<sym>     (BFD_RELOC_LO16)
              <op>   $treg,0($tempreg)
            If there is a base register, we add it to $tempreg before
            the <op>.  If there is a constant, we stick it in the
            <op> instruction.  We don't handle constants larger than
            16 bits, because we have no way to load the upper 16 bits
            (actually, we could handle them for the subset of cases
            in which we are not using $at).  */
         assert (offset_expr.X_op == O_symbol);
         expr1.X_add_number = offset_expr.X_add_number;
         offset_expr.X_add_number = 0;
         if (expr1.X_add_number < -0x8000
             || expr1.X_add_number >= 0x8000)
           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
         gpdelay = reg_needs_delay (mips_gp_register);
         relax_start (offset_expr.X_add_symbol);
         macro_build (&offset_expr, "lui", "t,u", tempreg,
                     BFD_RELOC_MIPS_GOT_HI16);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
                     mips_gp_register);
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     BFD_RELOC_MIPS_GOT_LO16, tempreg);
         relax_switch ();
         if (gpdelay)
           macro_build (NULL, "nop", "");
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     BFD_RELOC_MIPS_GOT16, mips_gp_register);
         load_delay_nop ();
         macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
                     tempreg, BFD_RELOC_LO16);
         relax_end ();

         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                      tempreg, tempreg, breg);
         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
       }
      else if (mips_big_got && HAVE_NEWABI)
       {
         /* If this is a reference to an external symbol, we want
              lui    $tempreg,<sym>              (BFD_RELOC_MIPS_GOT_HI16)
              add    $tempreg,$tempreg,$gp
              lw     $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
              <op>   $treg,<ofst>($tempreg)
            Otherwise, for local symbols, we want:
              lw     $tempreg,<sym>($gp)  (BFD_RELOC_MIPS_GOT_PAGE)
              <op>   $treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
         assert (offset_expr.X_op == O_symbol);
         expr1.X_add_number = offset_expr.X_add_number;
         offset_expr.X_add_number = 0;
         if (expr1.X_add_number < -0x8000
             || expr1.X_add_number >= 0x8000)
           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
         relax_start (offset_expr.X_add_symbol);
         macro_build (&offset_expr, "lui", "t,u", tempreg,
                     BFD_RELOC_MIPS_GOT_HI16);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
                     mips_gp_register);
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     BFD_RELOC_MIPS_GOT_LO16, tempreg);
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                      tempreg, tempreg, breg);
         macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);

         relax_switch ();
         offset_expr.X_add_number = expr1.X_add_number;
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                     BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                      tempreg, tempreg, breg);
         macro_build (&offset_expr, s, fmt, treg,
                     BFD_RELOC_MIPS_GOT_OFST, tempreg);
         relax_end ();
       }
      else
       abort ();

      break;

    case M_LI:
    case M_LI_S:
      load_register (treg, &imm_expr, 0);
      break;

    case M_DLI:
      load_register (treg, &imm_expr, 1);
      break;

    case M_LI_SS:
      if (imm_expr.X_op == O_constant)
       {
         used_at = 1;
         load_register (AT, &imm_expr, 0);
         macro_build (NULL, "mtc1", "t,G", AT, treg);
         break;
       }
      else
       {
         assert (offset_expr.X_op == O_symbol
                && strcmp (segment_name (S_GET_SEGMENT
                                      (offset_expr.X_add_symbol)),
                          ".lit4") == 0
                && offset_expr.X_add_number == 0);
         macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
                     BFD_RELOC_MIPS_LITERAL, mips_gp_register);
         break;
       }

    case M_LI_D:
      /* Check if we have a constant in IMM_EXPR.  If the GPRs are 64 bits
         wide, IMM_EXPR is the entire value.  Otherwise IMM_EXPR is the high
         order 32 bits of the value and the low order 32 bits are either
         zero or in OFFSET_EXPR.  */
      if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
       {
         if (HAVE_64BIT_GPRS)
           load_register (treg, &imm_expr, 1);
         else
           {
             int hreg, lreg;

             if (target_big_endian)
              {
                hreg = treg;
                lreg = treg + 1;
              }
             else
              {
                hreg = treg + 1;
                lreg = treg;
              }

             if (hreg <= 31)
              load_register (hreg, &imm_expr, 0);
             if (lreg <= 31)
              {
                if (offset_expr.X_op == O_absent)
                  move_register (lreg, 0);
                else
                  {
                    assert (offset_expr.X_op == O_constant);
                    load_register (lreg, &offset_expr, 0);
                  }
              }
           }
         break;
       }

      /* We know that sym is in the .rdata section.  First we get the
        upper 16 bits of the address.  */
      if (mips_pic == NO_PIC)
       {
         macro_build_lui (&offset_expr, AT);
         used_at = 1;
       }
      else
       {
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
                     BFD_RELOC_MIPS_GOT16, mips_gp_register);
         used_at = 1;
       }

      /* Now we load the register(s).  */
      if (HAVE_64BIT_GPRS)
       {
         used_at = 1;
         macro_build (&offset_expr, "ld", "t,o(b)", treg, BFD_RELOC_LO16, AT);
       }
      else
       {
         used_at = 1;
         macro_build (&offset_expr, "lw", "t,o(b)", treg, BFD_RELOC_LO16, AT);
         if (treg != RA)
           {
             /* FIXME: How in the world do we deal with the possible
               overflow here?  */
             offset_expr.X_add_number += 4;
             macro_build (&offset_expr, "lw", "t,o(b)",
                        treg + 1, BFD_RELOC_LO16, AT);
           }
       }
      break;

    case M_LI_DD:
      /* Check if we have a constant in IMM_EXPR.  If the FPRs are 64 bits
         wide, IMM_EXPR is the entire value and the GPRs are known to be 64
         bits wide as well.  Otherwise IMM_EXPR is the high order 32 bits of
         the value and the low order 32 bits are either zero or in
         OFFSET_EXPR.  */
      if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
       {
         used_at = 1;
         load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
         if (HAVE_64BIT_FPRS)
           {
             assert (HAVE_64BIT_GPRS);
             macro_build (NULL, "dmtc1", "t,S", AT, treg);
           }
         else
           {
             macro_build (NULL, "mtc1", "t,G", AT, treg + 1);
             if (offset_expr.X_op == O_absent)
              macro_build (NULL, "mtc1", "t,G", 0, treg);
             else
              {
                assert (offset_expr.X_op == O_constant);
                load_register (AT, &offset_expr, 0);
                macro_build (NULL, "mtc1", "t,G", AT, treg);
              }
           }
         break;
       }

      assert (offset_expr.X_op == O_symbol
             && offset_expr.X_add_number == 0);
      s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
      if (strcmp (s, ".lit8") == 0)
       {
         if (mips_opts.isa != ISA_MIPS1)
           {
             macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
                        BFD_RELOC_MIPS_LITERAL, mips_gp_register);
             break;
           }
         breg = mips_gp_register;
         r = BFD_RELOC_MIPS_LITERAL;
         goto dob;
       }
      else
       {
         assert (strcmp (s, RDATA_SECTION_NAME) == 0);
         used_at = 1;
         if (mips_pic != NO_PIC)
           macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
                      BFD_RELOC_MIPS_GOT16, mips_gp_register);
         else
           {
             /* FIXME: This won't work for a 64 bit address.  */
             macro_build_lui (&offset_expr, AT);
           }

         if (mips_opts.isa != ISA_MIPS1)
           {
             macro_build (&offset_expr, "ldc1", "T,o(b)",
                        treg, BFD_RELOC_LO16, AT);
             break;
           }
         breg = AT;
         r = BFD_RELOC_LO16;
         goto dob;
       }

    case M_L_DOB:
      if (mips_opts.arch == CPU_R4650)
       {
         as_bad (_("opcode not supported on this processor"));
         break;
       }
      /* Even on a big endian machine $fn comes before $fn+1.  We have
        to adjust when loading from memory.  */
      r = BFD_RELOC_LO16;
    dob:
      assert (mips_opts.isa == ISA_MIPS1);
      macro_build (&offset_expr, "lwc1", "T,o(b)",
                 target_big_endian ? treg + 1 : treg, r, breg);
      /* FIXME: A possible overflow which I don't know how to deal
        with.  */
      offset_expr.X_add_number += 4;
      macro_build (&offset_expr, "lwc1", "T,o(b)",
                 target_big_endian ? treg : treg + 1, r, breg);
      break;

    case M_L_DAB:
      /*
       * The MIPS assembler seems to check for X_add_number not
       * being double aligned and generating:
       *      lui    at,%hi(foo+1)
       *      addu   at,at,v1
       *      addiu  at,at,%lo(foo+1)
       *      lwc1   f2,0(at)
       *      lwc1   f3,4(at)
       * But, the resulting address is the same after relocation so why
       * generate the extra instruction?
       */
      if (mips_opts.arch == CPU_R4650)
       {
         as_bad (_("opcode not supported on this processor"));
         break;
       }
      /* Itbl support may require additional care here.  */
      coproc = 1;
      if (mips_opts.isa != ISA_MIPS1)
       {
         s = "ldc1";
         goto ld;
       }

      s = "lwc1";
      fmt = "T,o(b)";
      goto ldd_std;

    case M_S_DAB:
      if (mips_opts.arch == CPU_R4650)
       {
         as_bad (_("opcode not supported on this processor"));
         break;
       }

      if (mips_opts.isa != ISA_MIPS1)
       {
         s = "sdc1";
         goto st;
       }

      s = "swc1";
      fmt = "T,o(b)";
      /* Itbl support may require additional care here.  */
      coproc = 1;
      goto ldd_std;

    case M_LD_AB:
      if (HAVE_64BIT_GPRS)
       {
         s = "ld";
         goto ld;
       }

      s = "lw";
      fmt = "t,o(b)";
      goto ldd_std;

    case M_SD_AB:
      if (HAVE_64BIT_GPRS)
       {
         s = "sd";
         goto st;
       }

      s = "sw";
      fmt = "t,o(b)";

    ldd_std:
      if (offset_expr.X_op != O_symbol
         && offset_expr.X_op != O_constant)
       {
         as_bad (_("expression too complex"));
         offset_expr.X_op = O_constant;
       }

      if (HAVE_32BIT_ADDRESSES
         && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
       {
         char value [32];

         sprintf_vma (value, offset_expr.X_add_number);
         as_bad (_("Number (0x%s) larger than 32 bits"), value);
       }

      /* Even on a big endian machine $fn comes before $fn+1.  We have
        to adjust when loading from memory.  We set coproc if we must
        load $fn+1 first.  */
      /* Itbl support may require additional care here.  */
      if (! target_big_endian)
       coproc = 0;

      if (mips_pic == NO_PIC
         || offset_expr.X_op == O_constant)
       {
         /* If this is a reference to a GP relative symbol, we want
              <op>   $treg,<sym>($gp)     (BFD_RELOC_GPREL16)
              <op>   $treg+1,<sym>+4($gp) (BFD_RELOC_GPREL16)
            If we have a base register, we use this
              addu   $at,$breg,$gp
              <op>   $treg,<sym>($at)     (BFD_RELOC_GPREL16)
              <op>   $treg+1,<sym>+4($at) (BFD_RELOC_GPREL16)
            If this is not a GP relative symbol, we want
              lui    $at,<sym>            (BFD_RELOC_HI16_S)
              <op>   $treg,<sym>($at)     (BFD_RELOC_LO16)
              <op>   $treg+1,<sym>+4($at) (BFD_RELOC_LO16)
            If there is a base register, we add it to $at after the
            lui instruction.  If there is a constant, we always use
            the last case.  */
         if (offset_expr.X_op == O_symbol
             && (valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
             && !nopic_need_relax (offset_expr.X_add_symbol, 1))
           {
             relax_start (offset_expr.X_add_symbol);
             if (breg == 0)
              {
                tempreg = mips_gp_register;
              }
             else
              {
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                            AT, breg, mips_gp_register);
                tempreg = AT;
                used_at = 1;
              }

             /* Itbl support may require additional care here.  */
             macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                        BFD_RELOC_GPREL16, tempreg);
             offset_expr.X_add_number += 4;

             /* Set mips_optimize to 2 to avoid inserting an
                 undesired nop.  */
             hold_mips_optimize = mips_optimize;
             mips_optimize = 2;
             /* Itbl support may require additional care here.  */
             macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                        BFD_RELOC_GPREL16, tempreg);
             mips_optimize = hold_mips_optimize;

             relax_switch ();

             /* We just generated two relocs.  When tc_gen_reloc
               handles this case, it will skip the first reloc and
               handle the second.  The second reloc already has an
               extra addend of 4, which we added above.  We must
               subtract it out, and then subtract another 4 to make
               the first reloc come out right.  The second reloc
               will come out right because we are going to add 4 to
               offset_expr when we build its instruction below.

               If we have a symbol, then we don't want to include
               the offset, because it will wind up being included
               when we generate the reloc.  */

             if (offset_expr.X_op == O_constant)
              offset_expr.X_add_number -= 8;
             else
              {
                offset_expr.X_add_number = -4;
                offset_expr.X_op = O_constant;
              }
           }
         used_at = 1;
         macro_build_lui (&offset_expr, AT);
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
         /* Itbl support may require additional care here.  */
         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                     BFD_RELOC_LO16, AT);
         /* FIXME: How do we handle overflow here?  */
         offset_expr.X_add_number += 4;
         /* Itbl support may require additional care here.  */
         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                     BFD_RELOC_LO16, AT);
         if (mips_relax.sequence)
           relax_end ();
       }
      else if (!mips_big_got)
       {
         /* If this is a reference to an external symbol, we want
              lw     $at,<sym>($gp)              (BFD_RELOC_MIPS_GOT16)
              nop
              <op>   $treg,0($at)
              <op>   $treg+1,4($at)
            Otherwise we want
              lw     $at,<sym>($gp)              (BFD_RELOC_MIPS_GOT16)
              nop
              <op>   $treg,<sym>($at)     (BFD_RELOC_LO16)
              <op>   $treg+1,<sym>+4($at) (BFD_RELOC_LO16)
            If there is a base register we add it to $at before the
            lwc1 instructions.  If there is a constant we include it
            in the lwc1 instructions.  */
         used_at = 1;
         expr1.X_add_number = offset_expr.X_add_number;
         if (expr1.X_add_number < -0x8000
             || expr1.X_add_number >= 0x8000 - 4)
           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
         load_got_offset (AT, &offset_expr);
         load_delay_nop ();
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);

         /* Set mips_optimize to 2 to avoid inserting an undesired
             nop.  */
         hold_mips_optimize = mips_optimize;
         mips_optimize = 2;

         /* Itbl support may require additional care here.  */
         relax_start (offset_expr.X_add_symbol);
         macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
                     BFD_RELOC_LO16, AT);
         expr1.X_add_number += 4;
         macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
                     BFD_RELOC_LO16, AT);
         relax_switch ();
         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                     BFD_RELOC_LO16, AT);
         offset_expr.X_add_number += 4;
         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                     BFD_RELOC_LO16, AT);
         relax_end ();

         mips_optimize = hold_mips_optimize;
       }
      else if (mips_big_got)
       {
         int gpdelay;

         /* If this is a reference to an external symbol, we want
              lui    $at,<sym>            (BFD_RELOC_MIPS_GOT_HI16)
              addu   $at,$at,$gp
              lw     $at,<sym>($at)              (BFD_RELOC_MIPS_GOT_LO16)
              nop
              <op>   $treg,0($at)
              <op>   $treg+1,4($at)
            Otherwise we want
              lw     $at,<sym>($gp)              (BFD_RELOC_MIPS_GOT16)
              nop
              <op>   $treg,<sym>($at)     (BFD_RELOC_LO16)
              <op>   $treg+1,<sym>+4($at) (BFD_RELOC_LO16)
            If there is a base register we add it to $at before the
            lwc1 instructions.  If there is a constant we include it
            in the lwc1 instructions.  */
         used_at = 1;
         expr1.X_add_number = offset_expr.X_add_number;
         offset_expr.X_add_number = 0;
         if (expr1.X_add_number < -0x8000
             || expr1.X_add_number >= 0x8000 - 4)
           as_bad (_("PIC code offset overflow (max 16 signed bits)"));
         gpdelay = reg_needs_delay (mips_gp_register);
         relax_start (offset_expr.X_add_symbol);
         macro_build (&offset_expr, "lui", "t,u",
                     AT, BFD_RELOC_MIPS_GOT_HI16);
         macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                     AT, AT, mips_gp_register);
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                     AT, BFD_RELOC_MIPS_GOT_LO16, AT);
         load_delay_nop ();
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
         /* Itbl support may require additional care here.  */
         macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
                     BFD_RELOC_LO16, AT);
         expr1.X_add_number += 4;

         /* Set mips_optimize to 2 to avoid inserting an undesired
             nop.  */
         hold_mips_optimize = mips_optimize;
         mips_optimize = 2;
         /* Itbl support may require additional care here.  */
         macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
                     BFD_RELOC_LO16, AT);
         mips_optimize = hold_mips_optimize;
         expr1.X_add_number -= 4;

         relax_switch ();
         offset_expr.X_add_number = expr1.X_add_number;
         if (gpdelay)
           macro_build (NULL, "nop", "");
         macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
                     BFD_RELOC_MIPS_GOT16, mips_gp_register);
         load_delay_nop ();
         if (breg != 0)
           macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
         /* Itbl support may require additional care here.  */
         macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
                     BFD_RELOC_LO16, AT);
         offset_expr.X_add_number += 4;

         /* Set mips_optimize to 2 to avoid inserting an undesired
             nop.  */
         hold_mips_optimize = mips_optimize;
         mips_optimize = 2;
         /* Itbl support may require additional care here.  */
         macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
                     BFD_RELOC_LO16, AT);
         mips_optimize = hold_mips_optimize;
         relax_end ();
       }
      else
       abort ();

      break;

    case M_LD_OB:
      s = "lw";
      goto sd_ob;
    case M_SD_OB:
      s = "sw";
    sd_ob:
      assert (HAVE_32BIT_ADDRESSES);
      macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
      offset_expr.X_add_number += 4;
      macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
      break;

   /* New code added to support COPZ instructions.
      This code builds table entries out of the macros in mip_opcodes.
      R4000 uses interlocks to handle coproc delays.
      Other chips (like the R3000) require nops to be inserted for delays.

      FIXME: Currently, we require that the user handle delays.
      In order to fill delay slots for non-interlocked chips,
      we must have a way to specify delays based on the coprocessor.
      Eg. 4 cycles if load coproc reg from memory, 1 if in cache, etc.
      What are the side-effects of the cop instruction?
      What cache support might we have and what are its effects?
      Both coprocessor & memory require delays. how long???
      What registers are read/set/modified?

      If an itbl is provided to interpret cop instructions,
      this knowledge can be encoded in the itbl spec.  */

    case M_COP0:
      s = "c0";
      goto copz;
    case M_COP1:
      s = "c1";
      goto copz;
    case M_COP2:
      s = "c2";
      goto copz;
    case M_COP3:
      s = "c3";
    copz:
      /* For now we just do C (same as Cz).  The parameter will be
         stored in insn_opcode by mips_ip.  */
      macro_build (NULL, s, "C", ip->insn_opcode);
      break;

    case M_MOVE:
      move_register (dreg, sreg);
      break;

#ifdef LOSING_COMPILER
    default:
      /* Try and see if this is a new itbl instruction.
         This code builds table entries out of the macros in mip_opcodes.
         FIXME: For now we just assemble the expression and pass it's
         value along as a 32-bit immediate.
         We may want to have the assembler assemble this value,
         so that we gain the assembler's knowledge of delay slots,
         symbols, etc.
         Would it be more efficient to use mask (id) here? */
      if (itbl_have_entries
         && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
       {
         s = ip->insn_mo->name;
         s2 = "cop3";
         coproc = ITBL_DECODE_PNUM (immed_expr);;
         macro_build (&immed_expr, s, "C");
         break;
       }
      macro2 (ip);
      break;
    }
  if (mips_opts.noat && used_at)
    as_bad (_("Macro used $at after \".set noat\""));
}

static void
macro2 (struct mips_cl_insn *ip)
{
  int treg, sreg, dreg, breg;
  int tempreg;
  int mask;
  int used_at;
  expressionS expr1;
  const char *s;
  const char *s2;
  const char *fmt;
  int likely = 0;
  int dbl = 0;
  int coproc = 0;
  int lr = 0;
  int imm = 0;
  int off;
  offsetT maxnum;
  bfd_reloc_code_real_type r;

  treg = (ip->insn_opcode >> 16) & 0x1f;
  dreg = (ip->insn_opcode >> 11) & 0x1f;
  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
  mask = ip->insn_mo->mask;

  expr1.X_op = O_constant;
  expr1.X_op_symbol = NULL;
  expr1.X_add_symbol = NULL;
  expr1.X_add_number = 1;

  switch (mask)
    {
#endif /* LOSING_COMPILER */

    case M_DMUL:
      dbl = 1;
    case M_MUL:
      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
      macro_build (NULL, "mflo", "d", dreg);
      break;

    case M_DMUL_I:
      dbl = 1;
    case M_MUL_I:
      /* The MIPS assembler some times generates shifts and adds.  I'm
        not trying to be that fancy. GCC should do this for us
        anyway.  */
      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
      macro_build (NULL, "mflo", "d", dreg);
      break;

    case M_DMULO_I:
      dbl = 1;
    case M_MULO_I:
      imm = 1;
      goto do_mulo;

    case M_DMULO:
      dbl = 1;
    case M_MULO:
    do_mulo:
      start_noreorder ();
      used_at = 1;
      if (imm)
       load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
      macro_build (NULL, "mflo", "d", dreg);
      macro_build (NULL, dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, RA);
      macro_build (NULL, "mfhi", "d", AT);
      if (mips_trap)
       macro_build (NULL, "tne", "s,t,q", dreg, AT, 6);
      else
       {
         expr1.X_add_number = 8;
         macro_build (&expr1, "beq", "s,t,p", dreg, AT);
         macro_build (NULL, "nop", "", 0);
         macro_build (NULL, "break", "c", 6);
       }
      end_noreorder ();
      macro_build (NULL, "mflo", "d", dreg);
      break;

    case M_DMULOU_I:
      dbl = 1;
    case M_MULOU_I:
      imm = 1;
      goto do_mulou;

    case M_DMULOU:
      dbl = 1;
    case M_MULOU:
    do_mulou:
      start_noreorder ();
      used_at = 1;
      if (imm)
       load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
                 sreg, imm ? AT : treg);
      macro_build (NULL, "mfhi", "d", AT);
      macro_build (NULL, "mflo", "d", dreg);
      if (mips_trap)
       macro_build (NULL, "tne", "s,t,q", AT, 0, 6);
      else
       {
         expr1.X_add_number = 8;
         macro_build (&expr1, "beq", "s,t,p", AT, 0);
         macro_build (NULL, "nop", "", 0);
         macro_build (NULL, "break", "c", 6);
       }
      end_noreorder ();
      break;

    case M_DROL:
      if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
       {
         if (dreg == sreg)
           {
             tempreg = AT;
             used_at = 1;
           }
         else
           {
             tempreg = dreg;
           }
         macro_build (NULL, "dnegu", "d,w", tempreg, treg);
         macro_build (NULL, "drorv", "d,t,s", dreg, sreg, tempreg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
      macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
      macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      break;

    case M_ROL:
      if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
       {
         if (dreg == sreg)
           {
             tempreg = AT;
             used_at = 1;
           }
         else
           {
             tempreg = dreg;
           }
         macro_build (NULL, "negu", "d,w", tempreg, treg);
         macro_build (NULL, "rorv", "d,t,s", dreg, sreg, tempreg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
      macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
      macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      break;

    case M_DROL_I:
      {
       unsigned int rot;
       char *l, *r;

       if (imm_expr.X_op != O_constant)
         as_bad (_("Improper rotate count"));
       rot = imm_expr.X_add_number & 0x3f;
       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
         {
           rot = (64 - rot) & 0x3f;
           if (rot >= 32)
             macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
           else
             macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
           break;
         }
       if (rot == 0)
         {
           macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
           break;
         }
       l = (rot < 0x20) ? "dsll" : "dsll32";
       r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
       rot &= 0x1f;
       used_at = 1;
       macro_build (NULL, l, "d,w,<", AT, sreg, rot);
       macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      break;

    case M_ROL_I:
      {
       unsigned int rot;

       if (imm_expr.X_op != O_constant)
         as_bad (_("Improper rotate count"));
       rot = imm_expr.X_add_number & 0x1f;
       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
         {
           macro_build (NULL, "ror", "d,w,<", dreg, sreg, (32 - rot) & 0x1f);
           break;
         }
       if (rot == 0)
         {
           macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
           break;
         }
       used_at = 1;
       macro_build (NULL, "sll", "d,w,<", AT, sreg, rot);
       macro_build (NULL, "srl", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      break;

    case M_DROR:
      if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
       {
         macro_build (NULL, "drorv", "d,t,s", dreg, sreg, treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
      macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
      macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      break;

    case M_ROR:
      if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
       {
         macro_build (NULL, "rorv", "d,t,s", dreg, sreg, treg);
         break;
       }
      used_at = 1;
      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
      macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
      macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      break;

    case M_DROR_I:
      {
       unsigned int rot;
       char *l, *r;

       if (imm_expr.X_op != O_constant)
         as_bad (_("Improper rotate count"));
       rot = imm_expr.X_add_number & 0x3f;
       if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
         {
           if (rot >= 32)
             macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
           else
             macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
           break;
         }
       if (rot == 0)
         {
           macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
           break;
         }
       r = (rot < 0x20) ? "dsrl" : "dsrl32";
       l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
       rot &= 0x1f;
       used_at = 1;
       macro_build (NULL, r, "d,w,<", AT, sreg, rot);
       macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      break;

    case M_ROR_I:
      {
       unsigned int rot;

       if (imm_expr.X_op != O_constant)
         as_bad (_("Improper rotate count"));
       rot = imm_expr.X_add_number & 0x1f;
       if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
         {
           macro_build (NULL, "ror", "d,w,<", dreg, sreg, rot);
           break;
         }
       if (rot == 0)
         {
           macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
           break;
         }
       used_at = 1;
       macro_build (NULL, "srl", "d,w,<", AT, sreg, rot);
       macro_build (NULL, "sll", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
       macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      break;

    case M_S_DOB:
      if (mips_opts.arch == CPU_R4650)
       {
         as_bad (_("opcode not supported on this processor"));
         break;
       }
      assert (mips_opts.isa == ISA_MIPS1);
      /* Even on a big endian machine $fn comes before $fn+1.  We have
        to adjust when storing to memory.  */
      macro_build (&offset_expr, "swc1", "T,o(b)",
                 target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
      offset_expr.X_add_number += 4;
      macro_build (&offset_expr, "swc1", "T,o(b)",
                 target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
      break;

    case M_SEQ:
      if (sreg == 0)
       macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
      else if (treg == 0)
       macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
      else
       {
         macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
         macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
       }
      break;

    case M_SEQ_I:
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       {
         macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
         break;
       }
      if (sreg == 0)
       {
         as_warn (_("Instruction %s: result is always false"),
                 ip->insn_mo->name);
         move_register (dreg, 0);
         break;
       }
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= 0
         && imm_expr.X_add_number < 0x10000)
       {
         macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
       }
      else if (imm_expr.X_op == O_constant
              && imm_expr.X_add_number > -0x8000
              && imm_expr.X_add_number < 0)
       {
         imm_expr.X_add_number = -imm_expr.X_add_number;
         macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
                     "t,r,j", dreg, sreg, BFD_RELOC_LO16);
       }
      else
       {
         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
         macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
         used_at = 1;
       }
      macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
      break;

    case M_SGE:             /* sreg >= treg <==> not (sreg < treg) */
      s = "slt";
      goto sge;
    case M_SGEU:
      s = "sltu";
    sge:
      macro_build (NULL, s, "d,v,t", dreg, sreg, treg);
      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
      break;

    case M_SGE_I:           /* sreg >= I <==> not (sreg < I) */
    case M_SGEU_I:
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= -0x8000
         && imm_expr.X_add_number < 0x8000)
       {
         macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
                     dreg, sreg, BFD_RELOC_LO16);
       }
      else
       {
         load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
         macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
                     dreg, sreg, AT);
         used_at = 1;
       }
      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
      break;

    case M_SGT:             /* sreg > treg  <==>  treg < sreg */
      s = "slt";
      goto sgt;
    case M_SGTU:
      s = "sltu";
    sgt:
      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
      break;

    case M_SGT_I:           /* sreg > I  <==>  I < sreg */
      s = "slt";
      goto sgti;
    case M_SGTU_I:
      s = "sltu";
    sgti:
      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
      break;

    case M_SLE:      /* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
      s = "slt";
      goto sle;
    case M_SLEU:
      s = "sltu";
    sle:
      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
      break;

    case M_SLE_I:    /* sreg <= I <==> I >= sreg <==> not (I < sreg) */
      s = "slt";
      goto slei;
    case M_SLEU_I:
      s = "sltu";
    slei:
      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
      break;

    case M_SLT_I:
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= -0x8000
         && imm_expr.X_add_number < 0x8000)
       {
         macro_build (&imm_expr, "slti", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
         break;
       }
      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (NULL, "slt", "d,v,t", dreg, sreg, AT);
      break;

    case M_SLTU_I:
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= -0x8000
         && imm_expr.X_add_number < 0x8000)
       {
         macro_build (&imm_expr, "sltiu", "t,r,j", dreg, sreg,
                     BFD_RELOC_LO16);
         break;
       }
      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (NULL, "sltu", "d,v,t", dreg, sreg, AT);
      break;

    case M_SNE:
      if (sreg == 0)
       macro_build (NULL, "sltu", "d,v,t", dreg, 0, treg);
      else if (treg == 0)
       macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
      else
       {
         macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
         macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
       }
      break;

    case M_SNE_I:
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
       {
         macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
         break;
       }
      if (sreg == 0)
       {
         as_warn (_("Instruction %s: result is always true"),
                 ip->insn_mo->name);
         macro_build (&expr1, HAVE_32BIT_GPRS ? "addiu" : "daddiu", "t,r,j",
                     dreg, 0, BFD_RELOC_LO16);
         break;
       }
      if (imm_expr.X_op == O_constant
         && imm_expr.X_add_number >= 0
         && imm_expr.X_add_number < 0x10000)
       {
         macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
       }
      else if (imm_expr.X_op == O_constant
              && imm_expr.X_add_number > -0x8000
              && imm_expr.X_add_number < 0)
       {
         imm_expr.X_add_number = -