OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gas/] [config/] [tc-mips.c] - Diff between revs 16 and 160

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 16 Rev 160
Line 89... Line 89...
static char *mips_regmask_frag;
static char *mips_regmask_frag;
#endif
#endif
 
 
#define ZERO 0
#define ZERO 0
#define ATREG 1
#define ATREG 1
 
#define S0  16
 
#define S7  23
#define TREG 24
#define TREG 24
#define PIC_CALL_REG 25
#define PIC_CALL_REG 25
#define KT0 26
#define KT0 26
#define KT1 27
#define KT1 27
#define GP  28
#define GP  28
Line 119... Line 121...
                            ? ".rdata" \
                            ? ".rdata" \
                            : OUTPUT_FLAVOR == bfd_target_elf_flavour \
                            : OUTPUT_FLAVOR == bfd_target_elf_flavour \
                            ? ".rodata" \
                            ? ".rodata" \
                            : (abort (), ""))
                            : (abort (), ""))
 
 
 
/* Ways in which an instruction can be "appended" to the output.  */
 
enum append_method {
 
  /* Just add it normally.  */
 
  APPEND_ADD,
 
 
 
  /* Add it normally and then add a nop.  */
 
  APPEND_ADD_WITH_NOP,
 
 
 
  /* Turn an instruction with a delay slot into a "compact" version.  */
 
  APPEND_ADD_COMPACT,
 
 
 
  /* Insert the instruction before the last one.  */
 
  APPEND_SWAP
 
};
 
 
/* Information about an instruction, including its format, operands
/* Information about an instruction, including its format, operands
   and fixups.  */
   and fixups.  */
struct mips_cl_insn
struct mips_cl_insn
{
{
  /* The opcode's entry in mips_opcodes or mips16_opcodes.  */
  /* The opcode's entry in mips_opcodes or mips16_opcodes.  */
Line 199... Line 216...
  int ase_mdmx;
  int ase_mdmx;
  int ase_smartmips;
  int ase_smartmips;
  int ase_dsp;
  int ase_dsp;
  int ase_dspr2;
  int ase_dspr2;
  int ase_mt;
  int ase_mt;
 
  int ase_mcu;
  /* Whether we are assembling for the mips16 processor.  0 if we are
  /* Whether we are assembling for the mips16 processor.  0 if we are
     not, 1 if we are, and -1 if the value has not been initialized.
     not, 1 if we are, and -1 if the value has not been initialized.
     Changed by `.set mips16' and `.set nomips16', and the -mips16 and
     Changed by `.set mips16' and `.set nomips16', and the -mips16 and
     -nomips16 command line options, and the default CPU.  */
     -nomips16 command line options, and the default CPU.  */
  int mips16;
  int mips16;
 
  /* Whether we are assembling for the mipsMIPS ASE.  0 if we are not,
 
     1 if we are, and -1 if the value has not been initialized.  Changed
 
     by `.set micromips' and `.set nomicromips', and the -mmicromips
 
     and -mno-micromips command line options, and the default CPU.  */
 
  int micromips;
  /* Non-zero if we should not reorder instructions.  Changed by `.set
  /* Non-zero if we should not reorder instructions.  Changed by `.set
     reorder' and `.set noreorder'.  */
     reorder' and `.set noreorder'.  */
  int noreorder;
  int noreorder;
  /* Non-zero if we should not permit the register designated "assembler
  /* Non-zero if we should not permit the register designated "assembler
     temporary" to be used in instructions.  The value is the register
     temporary" to be used in instructions.  The value is the register
Line 268... Line 291...
 
 
static struct mips_set_options mips_opts =
static struct mips_set_options mips_opts =
{
{
  /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
  /* isa */ ISA_UNKNOWN, /* ase_mips3d */ -1, /* ase_mdmx */ -1,
  /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
  /* ase_smartmips */ 0, /* ase_dsp */ -1, /* ase_dspr2 */ -1, /* ase_mt */ -1,
  /* mips16 */ -1, /* noreorder */ 0, /* at */ ATREG,
  /* ase_mcu */ -1, /* mips16 */ -1, /* micromips */ -1, /* noreorder */ 0,
  /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
  /* at */ ATREG, /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0,
  /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
  /* noautoextend */ 0, /* gp32 */ 0, /* fp32 */ 0, /* arch */ CPU_UNKNOWN,
  /* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
  /* sym32 */ FALSE, /* soft_float */ FALSE, /* single_float */ FALSE
};
};
 
 
/* These variables are filled in with the masks of registers used.
/* These variables are filled in with the masks of registers used.
Line 291... Line 314...
#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32               \
#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32               \
                              || mips_opts.isa == ISA_MIPS32R2          \
                              || mips_opts.isa == ISA_MIPS32R2          \
                              || mips_opts.isa == ISA_MIPS64            \
                              || mips_opts.isa == ISA_MIPS64            \
                              || mips_opts.isa == ISA_MIPS64R2)
                              || mips_opts.isa == ISA_MIPS64R2)
 
 
 
/* True if any microMIPS code was produced.  */
 
static int file_ase_micromips;
 
 
/* True if we want to create R_MIPS_JALR for jalr $25.  */
/* True if we want to create R_MIPS_JALR for jalr $25.  */
#ifdef TE_IRIX
#ifdef TE_IRIX
#define MIPS_JALR_HINT_P(EXPR) HAVE_NEWABI
#define MIPS_JALR_HINT_P(EXPR) HAVE_NEWABI
#else
#else
/* As a GNU extension, we use R_MIPS_JALR for o32 too.  However,
/* As a GNU extension, we use R_MIPS_JALR for o32 too.  However,
Line 341... Line 367...
static int file_ase_mt;
static int file_ase_mt;
 
 
#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2              \
#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2              \
                             || mips_opts.isa == ISA_MIPS64R2)
                             || mips_opts.isa == ISA_MIPS64R2)
 
 
 
#define ISA_SUPPORTS_MCU_ASE (mips_opts.isa == ISA_MIPS32R2             \
 
                              || mips_opts.isa == ISA_MIPS64R2)
 
 
/* The argument of the -march= flag.  The architecture we are assembling.  */
/* The argument of the -march= flag.  The architecture we are assembling.  */
static int file_mips_arch = CPU_UNKNOWN;
static int file_mips_arch = CPU_UNKNOWN;
static const char *mips_arch_string;
static const char *mips_arch_string;
 
 
/* The argument of the -mtune= flag.  The architecture for which we
/* The argument of the -mtune= flag.  The architecture for which we
Line 382... Line 411...
   || (ISA) == ISA_MIPS64R2)
   || (ISA) == ISA_MIPS64R2)
 
 
/* Return true if ISA supports 64-bit right rotate (dror et al.)
/* Return true if ISA supports 64-bit right rotate (dror et al.)
   instructions.  */
   instructions.  */
#define ISA_HAS_DROR(ISA)               \
#define ISA_HAS_DROR(ISA)               \
  ((ISA) == ISA_MIPS64R2)
  ((ISA) == ISA_MIPS64R2                \
 
   || (mips_opts.micromips              \
 
       && ISA_HAS_64BIT_REGS (ISA))     \
 
   )
 
 
/* Return true if ISA supports 32-bit right rotate (ror et al.)
/* Return true if ISA supports 32-bit right rotate (ror et al.)
   instructions.  */
   instructions.  */
#define ISA_HAS_ROR(ISA)                \
#define ISA_HAS_ROR(ISA)                \
  ((ISA) == ISA_MIPS32R2                \
  ((ISA) == ISA_MIPS32R2                \
   || (ISA) == ISA_MIPS64R2             \
   || (ISA) == ISA_MIPS64R2             \
   || mips_opts.ase_smartmips)
   || mips_opts.ase_smartmips           \
 
   || mips_opts.micromips               \
 
   )
 
 
/* Return true if ISA supports single-precision floats in odd registers.  */
/* Return true if ISA supports single-precision floats in odd registers.  */
#define ISA_HAS_ODD_SINGLE_FPR(ISA)     \
#define ISA_HAS_ODD_SINGLE_FPR(ISA)     \
  ((ISA) == ISA_MIPS32                  \
  ((ISA) == ISA_MIPS32                  \
   || (ISA) == ISA_MIPS32R2             \
   || (ISA) == ISA_MIPS32R2             \
Line 451... Line 485...
/* Return true if the given CPU supports the MIPS16 ASE.  */
/* Return true if the given CPU supports the MIPS16 ASE.  */
#define CPU_HAS_MIPS16(cpu)                                             \
#define CPU_HAS_MIPS16(cpu)                                             \
   (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0           \
   (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0           \
    || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
    || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
 
 
 
/* Return true if the given CPU supports the microMIPS ASE.  */
 
#define CPU_HAS_MICROMIPS(cpu)  0
 
 
/* True if CPU has a dror instruction.  */
/* True if CPU has a dror instruction.  */
#define CPU_HAS_DROR(CPU)       ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
#define CPU_HAS_DROR(CPU)       ((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
 
 
/* True if CPU has a ror instruction.  */
/* True if CPU has a ror instruction.  */
#define CPU_HAS_ROR(CPU)        CPU_HAS_DROR (CPU)
#define CPU_HAS_ROR(CPU)        CPU_HAS_DROR (CPU)
Line 489... Line 526...
   || mips_opts.arch == CPU_R12000                    \
   || mips_opts.arch == CPU_R12000                    \
   || mips_opts.arch == CPU_R14000                    \
   || mips_opts.arch == CPU_R14000                    \
   || mips_opts.arch == CPU_R16000                    \
   || mips_opts.arch == CPU_R16000                    \
   || mips_opts.arch == CPU_RM7000                    \
   || mips_opts.arch == CPU_RM7000                    \
   || mips_opts.arch == CPU_VR5500                    \
   || mips_opts.arch == CPU_VR5500                    \
 
   || mips_opts.micromips                             \
   )
   )
 
 
/* Whether the processor uses hardware interlocks to protect reads
/* Whether the processor uses hardware interlocks to protect reads
   from the GPRs after they are loaded from memory, and thus does not
   from the GPRs after they are loaded from memory, and thus does not
   require nops to be inserted.  This applies to instructions marked
   require nops to be inserted.  This applies to instructions marked
   INSN_LOAD_MEMORY_DELAY.  These nops are only required at MIPS ISA
   INSN_LOAD_MEMORY_DELAY.  These nops are only required at MIPS ISA
   level I.  */
   level I and microMIPS mode instructions are always interlocked.  */
#define gpr_interlocks \
#define gpr_interlocks \
  (mips_opts.isa != ISA_MIPS1  \
  (mips_opts.isa != ISA_MIPS1  \
   || mips_opts.arch == CPU_R3900)
   || mips_opts.arch == CPU_R3900                     \
 
   || mips_opts.micromips                             \
 
   )
 
 
/* Whether the processor uses hardware interlocks to avoid delays
/* Whether the processor uses hardware interlocks to avoid delays
   required by coprocessor instructions, and thus does not require
   required by coprocessor instructions, and thus does not require
   nops to be inserted.  This applies to instructions marked
   nops to be inserted.  This applies to instructions marked
   INSN_LOAD_COPROC_DELAY, INSN_COPROC_MOVE_DELAY, and to delays
   INSN_LOAD_COPROC_DELAY, INSN_COPROC_MOVE_DELAY, and to delays
   between instructions marked INSN_WRITE_COND_CODE and ones marked
   between instructions marked INSN_WRITE_COND_CODE and ones marked
   INSN_READ_COND_CODE.  These nops are only required at MIPS ISA
   INSN_READ_COND_CODE.  These nops are only required at MIPS ISA
   levels I, II, and III.  */
   levels I, II, and III and microMIPS mode instructions are always
 
   interlocked.  */
/* Itbl support may require additional care here.  */
/* Itbl support may require additional care here.  */
#define cop_interlocks                                \
#define cop_interlocks                                \
  ((mips_opts.isa != ISA_MIPS1                        \
  ((mips_opts.isa != ISA_MIPS1                        \
    && mips_opts.isa != ISA_MIPS2                     \
    && mips_opts.isa != ISA_MIPS2                     \
    && mips_opts.isa != ISA_MIPS3)                    \
    && mips_opts.isa != ISA_MIPS3)                    \
   || mips_opts.arch == CPU_R4300                     \
   || mips_opts.arch == CPU_R4300                     \
 
   || mips_opts.micromips                             \
   )
   )
 
 
/* Whether the processor uses hardware interlocks to protect reads
/* Whether the processor uses hardware interlocks to protect reads
   from coprocessor registers after they are loaded from memory, and
   from coprocessor registers after they are loaded from memory, and
   thus does not require nops to be inserted.  This applies to
   thus does not require nops to be inserted.  This applies to
   instructions marked INSN_COPROC_MEMORY_DELAY.  These nops are only
   instructions marked INSN_COPROC_MEMORY_DELAY.  These nops are only
   requires at MIPS ISA level I.  */
   requires at MIPS ISA level I and microMIPS mode instructions are
#define cop_mem_interlocks (mips_opts.isa != ISA_MIPS1)
   always interlocked.  */
 
#define cop_mem_interlocks                            \
 
  (mips_opts.isa != ISA_MIPS1                         \
 
   || mips_opts.micromips                             \
 
   )
 
 
/* Is this a mfhi or mflo instruction?  */
/* Is this a mfhi or mflo instruction?  */
#define MF_HILO_INSN(PINFO) \
#define MF_HILO_INSN(PINFO) \
  ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
  ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
 
 
Line 535... Line 581...
#define COP_INSN(PINFO)                                                 \
#define COP_INSN(PINFO)                                                 \
  (PINFO != INSN_MACRO                                                  \
  (PINFO != INSN_MACRO                                                  \
   && ((PINFO) & (FP_S | FP_D)) == 0                                     \
   && ((PINFO) & (FP_S | FP_D)) == 0                                     \
   && ((PINFO) & (INSN_COP | INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)))
   && ((PINFO) & (INSN_COP | INSN_READ_COND_CODE | INSN_WRITE_COND_CODE)))
 
 
 
/* Whether code compression (either of the MIPS16 or the microMIPS ASEs)
 
   has been selected.  This implies, in particular, that addresses of text
 
   labels have their LSB set.  */
 
#define HAVE_CODE_COMPRESSION                                           \
 
  ((mips_opts.mips16 | mips_opts.micromips) != 0)
 
 
/* MIPS PIC level.  */
/* MIPS PIC level.  */
 
 
enum mips_pic_level mips_pic;
enum mips_pic_level mips_pic;
 
 
/* 1 if we should generate 32 bit offsets from the $gp register in
/* 1 if we should generate 32 bit offsets from the $gp register in
Line 591... Line 643...
static struct hash_control *op_hash = NULL;
static struct hash_control *op_hash = NULL;
 
 
/* The opcode hash table we use for the mips16.  */
/* The opcode hash table we use for the mips16.  */
static struct hash_control *mips16_op_hash = NULL;
static struct hash_control *mips16_op_hash = NULL;
 
 
 
/* The opcode hash table we use for the microMIPS ASE.  */
 
static struct hash_control *micromips_op_hash = NULL;
 
 
/* This array holds the chars that always start a comment.  If the
/* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful */
    pre-processor is disabled, these aren't very useful */
const char comment_chars[] = "#";
const char comment_chars[] = "#";
 
 
/* This array holds the chars that only start a comment at the beginning of
/* This array holds the chars that only start a comment at the beginning of
Line 680... Line 735...
   instruction further if we're thinking about using history[0] to
   instruction further if we're thinking about using history[0] to
   fill a branch delay slot.  */
   fill a branch delay slot.  */
static struct mips_cl_insn history[1 + MAX_NOPS];
static struct mips_cl_insn history[1 + MAX_NOPS];
 
 
/* Nop instructions used by emit_nop.  */
/* Nop instructions used by emit_nop.  */
static struct mips_cl_insn nop_insn, mips16_nop_insn;
static struct mips_cl_insn nop_insn;
 
static struct mips_cl_insn mips16_nop_insn;
 
static struct mips_cl_insn micromips_nop16_insn;
 
static struct mips_cl_insn micromips_nop32_insn;
 
 
/* The appropriate nop for the current mode.  */
/* The appropriate nop for the current mode.  */
#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn)
#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn \
 
                  : (mips_opts.micromips ? &micromips_nop16_insn : &nop_insn))
 
 
 
/* The size of NOP_INSN in bytes.  */
 
#define NOP_INSN_SIZE (HAVE_CODE_COMPRESSION ? 2 : 4)
 
 
/* If this is set, it points to a frag holding nop instructions which
/* If this is set, it points to a frag holding nop instructions which
   were inserted before the start of a noreorder section.  If those
   were inserted before the start of a noreorder section.  If those
   nops turn out to be unnecessary, the size of the frag can be
   nops turn out to be unnecessary, the size of the frag can be
   decreased.  */
   decreased.  */
Line 750... Line 812...
static const unsigned int mips16_to_32_reg_map[] =
static const unsigned int mips16_to_32_reg_map[] =
{
{
  16, 17, 2, 3, 4, 5, 6, 7
  16, 17, 2, 3, 4, 5, 6, 7
};
};
 
 
 
/* Map normal MIPS register numbers to microMIPS register numbers.  */
 
 
 
#define mips32_to_micromips_reg_b_map   mips32_to_16_reg_map
 
#define mips32_to_micromips_reg_c_map   mips32_to_16_reg_map
 
#define mips32_to_micromips_reg_d_map   mips32_to_16_reg_map
 
#define mips32_to_micromips_reg_e_map   mips32_to_16_reg_map
 
#define mips32_to_micromips_reg_f_map   mips32_to_16_reg_map
 
#define mips32_to_micromips_reg_g_map   mips32_to_16_reg_map
 
#define mips32_to_micromips_reg_l_map   mips32_to_16_reg_map
 
 
 
#define X ILLEGAL_REG
 
/* reg type h: 4, 5, 6.  */
 
static const int mips32_to_micromips_reg_h_map[] =
 
{
 
  X, X, X, X, 4, 5, 6, X,
 
  X, X, X, X, X, X, X, X,
 
  X, X, X, X, X, X, X, X,
 
  X, X, X, X, X, X, X, X
 
};
 
 
 
/* reg type m: 0, 17, 2, 3, 16, 18, 19, 20.  */
 
static const int mips32_to_micromips_reg_m_map[] =
 
{
 
  0, X, 2, 3, X, X, X, X,
 
  X, X, X, X, X, X, X, X,
 
  4, 1, 5, 6, 7, X, X, X,
 
  X, X, X, X, X, X, X, X
 
};
 
 
 
/* reg type q: 0, 2-7. 17.  */
 
static const int mips32_to_micromips_reg_q_map[] =
 
{
 
  0, X, 2, 3, 4, 5, 6, 7,
 
  X, X, X, X, X, X, X, X,
 
  X, 1, X, X, X, X, X, X,
 
  X, X, X, X, X, X, X, X
 
};
 
 
 
#define mips32_to_micromips_reg_n_map  mips32_to_micromips_reg_m_map
 
#undef X
 
 
 
/* Map microMIPS register numbers to normal MIPS register numbers.  */
 
 
 
#define micromips_to_32_reg_b_map       mips16_to_32_reg_map
 
#define micromips_to_32_reg_c_map       mips16_to_32_reg_map
 
#define micromips_to_32_reg_d_map       mips16_to_32_reg_map
 
#define micromips_to_32_reg_e_map       mips16_to_32_reg_map
 
#define micromips_to_32_reg_f_map       mips16_to_32_reg_map
 
#define micromips_to_32_reg_g_map       mips16_to_32_reg_map
 
 
 
/* The microMIPS registers with type h.  */
 
static const unsigned int micromips_to_32_reg_h_map[] =
 
{
 
  5, 5, 6, 4, 4, 4, 4, 4
 
};
 
 
 
/* The microMIPS registers with type i.  */
 
static const unsigned int micromips_to_32_reg_i_map[] =
 
{
 
  6, 7, 7, 21, 22, 5, 6, 7
 
};
 
 
 
#define micromips_to_32_reg_l_map       mips16_to_32_reg_map
 
 
 
/* The microMIPS registers with type m.  */
 
static const unsigned int micromips_to_32_reg_m_map[] =
 
{
 
  0, 17, 2, 3, 16, 18, 19, 20
 
};
 
 
 
#define micromips_to_32_reg_n_map      micromips_to_32_reg_m_map
 
 
 
/* The microMIPS registers with type q.  */
 
static const unsigned int micromips_to_32_reg_q_map[] =
 
{
 
  0, 17, 2, 3, 4, 5, 6, 7
 
};
 
 
 
/* microMIPS imm type B.  */
 
static const int micromips_imm_b_map[] =
 
{
 
  1, 4, 8, 12, 16, 20, 24, -1
 
};
 
 
 
/* microMIPS imm type C.  */
 
static const int micromips_imm_c_map[] =
 
{
 
  128, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 255, 32768, 65535
 
};
 
 
/* Classifies the kind of instructions we're interested in when
/* Classifies the kind of instructions we're interested in when
   implementing -mfix-vr4120.  */
   implementing -mfix-vr4120.  */
enum fix_vr4120_class
enum fix_vr4120_class
{
{
  FIX_VR4120_MACC,
  FIX_VR4120_MACC,
Line 831... Line 983...
 
 
   RELAX_DELAY_SLOT
   RELAX_DELAY_SLOT
        Like RELAX_NOMACRO, but indicates that the macro appears in a branch
        Like RELAX_NOMACRO, but indicates that the macro appears in a branch
        delay slot.
        delay slot.
 
 
 
   RELAX_DELAY_SLOT_16BIT
 
        Like RELAX_DELAY_SLOT, but indicates that the delay slot requires a
 
        16-bit instruction.
 
 
 
   RELAX_DELAY_SLOT_SIZE_FIRST
 
        Like RELAX_DELAY_SLOT, but indicates that the first implementation of
 
        the macro is of the wrong size for the branch delay slot.
 
 
 
   RELAX_DELAY_SLOT_SIZE_SECOND
 
        Like RELAX_DELAY_SLOT, but indicates that the second implementation of
 
        the macro is of the wrong size for the branch delay slot.
 
 
   The frag's "opcode" points to the first fixup for relaxable code.
   The frag's "opcode" points to the first fixup for relaxable code.
 
 
   Relaxable macros are generated using a sequence such as:
   Relaxable macros are generated using a sequence such as:
 
 
      relax_start (SYMBOL);
      relax_start (SYMBOL);
Line 851... Line 1015...
#define RELAX_SECOND(X) ((X) & 0xff)
#define RELAX_SECOND(X) ((X) & 0xff)
#define RELAX_USE_SECOND 0x10000
#define RELAX_USE_SECOND 0x10000
#define RELAX_SECOND_LONGER 0x20000
#define RELAX_SECOND_LONGER 0x20000
#define RELAX_NOMACRO 0x40000
#define RELAX_NOMACRO 0x40000
#define RELAX_DELAY_SLOT 0x80000
#define RELAX_DELAY_SLOT 0x80000
 
#define RELAX_DELAY_SLOT_16BIT 0x100000
 
#define RELAX_DELAY_SLOT_SIZE_FIRST 0x200000
 
#define RELAX_DELAY_SLOT_SIZE_SECOND 0x400000
 
 
/* Branch without likely bit.  If label is out of range, we turn:
/* Branch without likely bit.  If label is out of range, we turn:
 
 
        beq reg1, reg2, label
        beq reg1, reg2, label
        delay slot
        delay slot
Line 974... Line 1141...
#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
 
 
 
/* For microMIPS code, we use relaxation similar to one we use for
 
   MIPS16 code.  Some instructions that take immediate values support
 
   two encodings: a small one which takes some small value, and a
 
   larger one which takes a 16 bit value.  As some branches also follow
 
   this pattern, relaxing these values is required.
 
 
 
   We can assemble both microMIPS and normal MIPS code in a single
 
   object.  Therefore, we need to support this type of relaxation at
 
   the same time that we support the relaxation described above.  We
 
   use one of the high bits of the subtype field to distinguish these
 
   cases.
 
 
 
   The information we store for this type of relaxation is the argument
 
   code found in the opcode file for this relocation, the register
 
   selected as the assembler temporary, whether the branch is
 
   unconditional, whether it is compact, whether it stores the link
 
   address implicitly in $ra, whether relaxation of out-of-range 32-bit
 
   branches to a sequence of instructions is enabled, and whether the
 
   displacement of a branch is too large to fit as an immediate argument
 
   of a 16-bit and a 32-bit branch, respectively.  */
 
#define RELAX_MICROMIPS_ENCODE(type, at, uncond, compact, link, \
 
                               relax32, toofar16, toofar32)     \
 
  (0x40000000                                                   \
 
   | ((type) & 0xff)                                            \
 
   | (((at) & 0x1f) << 8)                                       \
 
   | ((uncond) ? 0x2000 : 0)                                     \
 
   | ((compact) ? 0x4000 : 0)                                    \
 
   | ((link) ? 0x8000 : 0)                                       \
 
   | ((relax32) ? 0x10000 : 0)                                   \
 
   | ((toofar16) ? 0x20000 : 0)                                  \
 
   | ((toofar32) ? 0x40000 : 0))
 
#define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000)
 
#define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff)
 
#define RELAX_MICROMIPS_AT(i) (((i) >> 8) & 0x1f)
 
#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x2000) != 0)
 
#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x4000) != 0)
 
#define RELAX_MICROMIPS_LINK(i) (((i) & 0x8000) != 0)
 
#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x10000) != 0)
 
 
 
#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x20000) != 0)
 
#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x20000)
 
#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x20000)
 
#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x40000) != 0)
 
#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x40000)
 
#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x40000)
 
 
/* Is the given value a sign-extended 32-bit value?  */
/* Is the given value a sign-extended 32-bit value?  */
#define IS_SEXT_32BIT_NUM(x)                                            \
#define IS_SEXT_32BIT_NUM(x)                                            \
  (((x) &~ (offsetT) 0x7fffffff) == 0                                    \
  (((x) &~ (offsetT) 0x7fffffff) == 0                                    \
   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))
   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))
 
 
/* Is the given value a sign-extended 16-bit value?  */
/* Is the given value a sign-extended 16-bit value?  */
#define IS_SEXT_16BIT_NUM(x)                                            \
#define IS_SEXT_16BIT_NUM(x)                                            \
  (((x) &~ (offsetT) 0x7fff) == 0                                        \
  (((x) &~ (offsetT) 0x7fff) == 0                                        \
   || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
   || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
 
 
 
/* Is the given value a sign-extended 12-bit value?  */
 
#define IS_SEXT_12BIT_NUM(x)                                            \
 
  (((((x) & 0xfff) ^ 0x800LL) - 0x800LL) == (x))
 
 
/* Is the given value a zero-extended 32-bit value?  Or a negated one?  */
/* Is the given value a zero-extended 32-bit value?  Or a negated one?  */
#define IS_ZEXT_32BIT_NUM(x)                                            \
#define IS_ZEXT_32BIT_NUM(x)                                            \
  (((x) &~ (offsetT) 0xffffffff) == 0                                    \
  (((x) &~ (offsetT) 0xffffffff) == 0                                    \
   || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
   || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
 
 
Line 1006... Line 1223...
   INSN is a mips_cl_insn structure and VALUE is evaluated exactly once.
   INSN is a mips_cl_insn structure and VALUE is evaluated exactly once.
 
 
   include/opcode/mips.h specifies operand fields using the macros
   include/opcode/mips.h specifies operand fields using the macros
   OP_MASK_<FIELD> and OP_SH_<FIELD>.  The MIPS16 equivalents start
   OP_MASK_<FIELD> and OP_SH_<FIELD>.  The MIPS16 equivalents start
   with "MIPS16OP" instead of "OP".  */
   with "MIPS16OP" instead of "OP".  */
#define INSERT_OPERAND(FIELD, INSN, VALUE) \
#define INSERT_OPERAND(MICROMIPS, FIELD, INSN, VALUE) \
  INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD)
  do \
 
    if (!(MICROMIPS)) \
 
      INSERT_BITS ((INSN).insn_opcode, VALUE, \
 
                   OP_MASK_##FIELD, OP_SH_##FIELD); \
 
    else \
 
      INSERT_BITS ((INSN).insn_opcode, VALUE, \
 
                   MICROMIPSOP_MASK_##FIELD, MICROMIPSOP_SH_##FIELD); \
 
  while (0)
#define MIPS16_INSERT_OPERAND(FIELD, INSN, VALUE) \
#define MIPS16_INSERT_OPERAND(FIELD, INSN, VALUE) \
  INSERT_BITS ((INSN).insn_opcode, VALUE, \
  INSERT_BITS ((INSN).insn_opcode, VALUE, \
                MIPS16OP_MASK_##FIELD, MIPS16OP_SH_##FIELD)
                MIPS16OP_MASK_##FIELD, MIPS16OP_SH_##FIELD)
 
 
/* Extract the operand given by FIELD from mips_cl_insn INSN.  */
/* Extract the operand given by FIELD from mips_cl_insn INSN.  */
#define EXTRACT_OPERAND(FIELD, INSN) \
#define EXTRACT_OPERAND(MICROMIPS, FIELD, INSN) \
  EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD)
  (!(MICROMIPS) \
 
   ? EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD) \
 
   : EXTRACT_BITS ((INSN).insn_opcode, \
 
                   MICROMIPSOP_MASK_##FIELD, MICROMIPSOP_SH_##FIELD))
#define MIPS16_EXTRACT_OPERAND(FIELD, INSN) \
#define MIPS16_EXTRACT_OPERAND(FIELD, INSN) \
  EXTRACT_BITS ((INSN).insn_opcode, \
  EXTRACT_BITS ((INSN).insn_opcode, \
                MIPS16OP_MASK_##FIELD, \
                MIPS16OP_MASK_##FIELD, \
                MIPS16OP_SH_##FIELD)
                MIPS16OP_SH_##FIELD)


 
/* Whether or not we are emitting a branch-likely macro.  */
 
static bfd_boolean emit_branch_likely_macro = FALSE;
 
 
/* Global variables used when generating relaxable macros.  See the
/* Global variables used when generating relaxable macros.  See the
   comment above RELAX_ENCODE for more details about how relaxation
   comment above RELAX_ENCODE for more details about how relaxation
   is used.  */
   is used.  */
static struct {
static struct {
  /* 0 if we're not emitting a relaxable macro.
  /* 0 if we're not emitting a relaxable macro.
Line 1046... Line 1276...
/* Global variables used to decide whether a macro needs a warning.  */
/* Global variables used to decide whether a macro needs a warning.  */
static struct {
static struct {
  /* True if the macro is in a branch delay slot.  */
  /* True if the macro is in a branch delay slot.  */
  bfd_boolean delay_slot_p;
  bfd_boolean delay_slot_p;
 
 
 
  /* Set to the length in bytes required if the macro is in a delay slot
 
     that requires a specific length of instruction, otherwise zero.  */
 
  unsigned int delay_slot_length;
 
 
  /* For relaxable macros, sizes[0] is the length of the first alternative
  /* For relaxable macros, sizes[0] is the length of the first alternative
     in bytes and sizes[1] is the length of the second alternative.
     in bytes and sizes[1] is the length of the second alternative.
     For non-relaxable macros, both elements give the length of the
     For non-relaxable macros, both elements give the length of the
     macro in bytes.  */
     macro in bytes.  */
  unsigned int sizes[2];
  unsigned int sizes[2];
 
 
 
  /* For relaxable macros, first_insn_sizes[0] is the length of the first
 
     instruction of the first alternative in bytes and first_insn_sizes[1]
 
     is the length of the first instruction of the second alternative.
 
     For non-relaxable macros, both elements give the length of the first
 
     instruction in bytes.
 
 
 
     Set to zero if we haven't yet seen the first instruction.  */
 
  unsigned int first_insn_sizes[2];
 
 
 
  /* For relaxable macros, insns[0] is the number of instructions for the
 
     first alternative and insns[1] is the number of instructions for the
 
     second alternative.
 
 
 
     For non-relaxable macros, both elements give the number of
 
     instructions for the macro.  */
 
  unsigned int insns[2];
 
 
  /* The first variant frag for this macro.  */
  /* The first variant frag for this macro.  */
  fragS *first_frag;
  fragS *first_frag;
} mips_macro_warning;
} mips_macro_warning;


/* Prototypes for static functions.  */
/* Prototypes for static functions.  */
Line 1064... Line 1315...
    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
 
 
enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
 
 
static void append_insn
static void append_insn
  (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *);
  (struct mips_cl_insn *, expressionS *, bfd_reloc_code_real_type *,
 
   bfd_boolean expansionp);
static void mips_no_prev_insn (void);
static void mips_no_prev_insn (void);
static void macro_build (expressionS *, const char *, const char *, ...);
static void macro_build (expressionS *, const char *, const char *, ...);
static void mips16_macro_build
static void mips16_macro_build
  (expressionS *, const char *, const char *, va_list *);
  (expressionS *, const char *, const char *, va_list *);
static void load_register (int, expressionS *, int);
static void load_register (int, expressionS *, int);
Line 1116... Line 1368...
static void s_mips_file (int);
static void s_mips_file (int);
static void s_mips_loc (int);
static void s_mips_loc (int);
static bfd_boolean pic_need_relax (symbolS *, asection *);
static bfd_boolean pic_need_relax (symbolS *, asection *);
static int relaxed_branch_length (fragS *, asection *, int);
static int relaxed_branch_length (fragS *, asection *, int);
static int validate_mips_insn (const struct mips_opcode *);
static int validate_mips_insn (const struct mips_opcode *);
 
static int validate_micromips_insn (const struct mips_opcode *);
 
static int relaxed_micromips_16bit_branch_length (fragS *, asection *, int);
 
static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
 
 
/* Table and functions used to map between CPU/ISA names, and
/* Table and functions used to map between CPU/ISA names, and
   ISA levels, and CPU numbers.  */
   ISA levels, and CPU numbers.  */
 
 
struct mips_cpu_info
struct mips_cpu_info
Line 1135... Line 1390...
#define MIPS_CPU_ASE_DSP        0x0004  /* CPU implements DSP 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_MT         0x0008  /* CPU implements MT ASE */
#define MIPS_CPU_ASE_MIPS3D     0x0010  /* CPU implements MIPS-3D 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_MDMX       0x0020  /* CPU implements MDMX ASE */
#define MIPS_CPU_ASE_DSPR2      0x0040  /* CPU implements DSP R2 ASE */
#define MIPS_CPU_ASE_DSPR2      0x0040  /* CPU implements DSP R2 ASE */
 
#define MIPS_CPU_ASE_MCU        0x0080  /* CPU implements MCU ASE */
 
 
static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
static const struct mips_cpu_info *mips_cpu_info_from_arch (int);


Line 1268... Line 1524...
 
 
static struct insn_label_list *free_insn_labels;
static struct insn_label_list *free_insn_labels;
#define label_list tc_segment_info_data.labels
#define label_list tc_segment_info_data.labels
 
 
static void mips_clear_insn_labels (void);
static void mips_clear_insn_labels (void);
 
static void mips_mark_labels (void);
 
static void mips_compressed_mark_labels (void);
 
 
static inline void
static inline void
mips_clear_insn_labels (void)
mips_clear_insn_labels (void)
{
{
  register struct insn_label_list **pl;
  register struct insn_label_list **pl;
Line 1286... Line 1544...
      *pl = si->label_list;
      *pl = si->label_list;
      si->label_list = NULL;
      si->label_list = NULL;
    }
    }
}
}
 
 
 
/* Mark instruction labels in MIPS16/microMIPS mode.  */
 
 
 
static inline void
 
mips_mark_labels (void)
 
{
 
  if (HAVE_CODE_COMPRESSION)
 
    mips_compressed_mark_labels ();
 
}


static char *expr_end;
static char *expr_end;
 
 
/* Expressions which appear in instructions.  These are set by
/* Expressions which appear in instructions.  These are set by
   mips_ip.  */
   mips_ip.  */
Line 1303... Line 1569...
static bfd_reloc_code_real_type imm_reloc[3]
static bfd_reloc_code_real_type imm_reloc[3]
  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
static bfd_reloc_code_real_type offset_reloc[3]
static bfd_reloc_code_real_type offset_reloc[3]
  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
 
/* These are set by mips16_ip if an explicit extension is used.  */
/* This is set to the resulting size of the instruction to be produced
 
   by mips16_ip if an explicit extension is used or by mips_ip if an
 
   explicit size is supplied.  */
 
 
static bfd_boolean mips16_small, mips16_ext;
static unsigned int forced_insn_length;
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
/* The pdr segment for per procedure frame/regmask info.  Not used for
/* The pdr segment for per procedure frame/regmask info.  Not used for
   ECOFF debugging.  */
   ECOFF debugging.  */
 
 
Line 1357... Line 1625...
      abort ();
      abort ();
      return NULL;
      return NULL;
    }
    }
}
}
 
 
 
/* Return the length of a microMIPS instruction in bytes.  If bits of
 
   the mask beyond the low 16 are 0, then it is a 16-bit instruction.
 
   Otherwise assume a 32-bit instruction; 48-bit instructions (0x1f
 
   major opcode) will require further modifications to the opcode
 
   table.  */
 
 
 
static inline unsigned int
 
micromips_insn_length (const struct mips_opcode *mo)
 
{
 
  return (mo->mask >> 16) == 0 ? 2 : 4;
 
}
 
 
/* Return the length of instruction INSN.  */
/* Return the length of instruction INSN.  */
 
 
static inline unsigned int
static inline unsigned int
insn_length (const struct mips_cl_insn *insn)
insn_length (const struct mips_cl_insn *insn)
{
{
  if (!mips_opts.mips16)
  if (mips_opts.micromips)
    return 4;
    return micromips_insn_length (insn->insn_mo);
 
  else if (mips_opts.mips16)
  return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
  return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
 
  else
 
    return 4;
}
}
 
 
/* Initialise INSN from opcode entry MO.  Leave its position unspecified.  */
/* Initialise INSN from opcode entry MO.  Leave its position unspecified.  */
 
 
static void
static void
Line 1388... Line 1671...
  insn->noreorder_p = (mips_opts.noreorder > 0);
  insn->noreorder_p = (mips_opts.noreorder > 0);
  insn->mips16_absolute_jump_p = 0;
  insn->mips16_absolute_jump_p = 0;
  insn->complete_p = 0;
  insn->complete_p = 0;
}
}
 
 
/* Record the current MIPS16 mode in now_seg.  */
/* Record the current MIPS16/microMIPS mode in now_seg.  */
 
 
static void
static void
mips_record_mips16_mode (void)
mips_record_compressed_mode (void)
{
{
  segment_info_type *si;
  segment_info_type *si;
 
 
  si = seg_info (now_seg);
  si = seg_info (now_seg);
  if (si->tc_segment_info_data.mips16 != mips_opts.mips16)
  if (si->tc_segment_info_data.mips16 != mips_opts.mips16)
    si->tc_segment_info_data.mips16 = mips_opts.mips16;
    si->tc_segment_info_data.mips16 = mips_opts.mips16;
 
  if (si->tc_segment_info_data.micromips != mips_opts.micromips)
 
    si->tc_segment_info_data.micromips = mips_opts.micromips;
}
}
 
 
/* Install INSN at the location specified by its "frag" and "where" fields.  */
/* Install INSN at the location specified by its "frag" and "where" fields.  */
 
 
static void
static void
install_insn (const struct mips_cl_insn *insn)
install_insn (const struct mips_cl_insn *insn)
{
{
  char *f = insn->frag->fr_literal + insn->where;
  char *f = insn->frag->fr_literal + insn->where;
  if (!mips_opts.mips16)
  if (!HAVE_CODE_COMPRESSION)
    md_number_to_chars (f, insn->insn_opcode, 4);
    md_number_to_chars (f, insn->insn_opcode, 4);
 
  else if (mips_opts.micromips)
 
    {
 
      unsigned int length = insn_length (insn);
 
      if (length == 2)
 
        md_number_to_chars (f, insn->insn_opcode, 2);
 
      else if (length == 4)
 
        {
 
          md_number_to_chars (f, insn->insn_opcode >> 16, 2);
 
          f += 2;
 
          md_number_to_chars (f, insn->insn_opcode & 0xffff, 2);
 
        }
 
      else
 
        as_bad (_("48-bit microMIPS instructions are not supported"));
 
    }
  else if (insn->mips16_absolute_jump_p)
  else if (insn->mips16_absolute_jump_p)
    {
    {
      md_number_to_chars (f, insn->insn_opcode >> 16, 2);
      md_number_to_chars (f, insn->insn_opcode >> 16, 2);
      md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
      md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
    }
    }
Line 1422... Line 1721...
          md_number_to_chars (f, 0xf000 | insn->extend, 2);
          md_number_to_chars (f, 0xf000 | insn->extend, 2);
          f += 2;
          f += 2;
        }
        }
      md_number_to_chars (f, insn->insn_opcode, 2);
      md_number_to_chars (f, insn->insn_opcode, 2);
    }
    }
  mips_record_mips16_mode ();
  mips_record_compressed_mode ();
}
}
 
 
/* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly
/* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly
   and install the opcode in the new location.  */
   and install the opcode in the new location.  */
 
 
Line 1486... Line 1785...
        else
        else
          history[i] = *insn;
          history[i] = *insn;
    }
    }
}
}
 
 
/* Emit a nop instruction, recording it in the history buffer.  */
 
 
 
static void
 
emit_nop (void)
 
{
 
  add_fixed_insn (NOP_INSN);
 
  insert_into_history (0, 1, NOP_INSN);
 
}
 
 
 
/* Initialize vr4120_conflicts.  There is a bit of duplication here:
/* Initialize vr4120_conflicts.  There is a bit of duplication here:
   the idea is to make it obvious at a glance that each errata is
   the idea is to make it obvious at a glance that each errata is
   included.  */
   included.  */
 
 
static void
static void
Line 1775... Line 2065...
static const struct regname reg_names_n32n64[] = {
static const struct regname reg_names_n32n64[] = {
  N32N64_SYMBOLIC_REGISTER_NAMES,
  N32N64_SYMBOLIC_REGISTER_NAMES,
  {0, 0}
  {0, 0}
};
};
 
 
 
/* Check if S points at a valid register specifier according to TYPES.
 
   If so, then return 1, advance S to consume the specifier and store
 
   the register's number in REGNOP, otherwise return 0.  */
 
 
static int
static int
reg_lookup (char **s, unsigned int types, unsigned int *regnop)
reg_lookup (char **s, unsigned int types, unsigned int *regnop)
{
{
  symbolS *symbolP;
  symbolS *symbolP;
  char *e;
  char *e;
Line 1828... Line 2122...
  if (regnop)
  if (regnop)
    *regnop = reg;
    *regnop = reg;
  return reg >= 0;
  return reg >= 0;
}
}
 
 
 
/* Check if S points at a valid register list according to TYPES.
 
   If so, then return 1, advance S to consume the list and store
 
   the registers present on the list as a bitmask of ones in REGLISTP,
 
   otherwise return 0.  A valid list comprises a comma-separated
 
   enumeration of valid single registers and/or dash-separated
 
   contiguous register ranges as determined by their numbers.
 
 
 
   As a special exception if one of s0-s7 registers is specified as
 
   the range's lower delimiter and s8 (fp) is its upper one, then no
 
   registers whose numbers place them between s7 and s8 (i.e. $24-$29)
 
   are selected; they have to be listed separately if needed.  */
 
 
 
static int
 
reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
 
{
 
  unsigned int reglist = 0;
 
  unsigned int lastregno;
 
  bfd_boolean ok = TRUE;
 
  unsigned int regmask;
 
  char *s_endlist = *s;
 
  char *s_reset = *s;
 
  unsigned int regno;
 
 
 
  while (reg_lookup (s, types, &regno))
 
    {
 
      lastregno = regno;
 
      if (**s == '-')
 
        {
 
          (*s)++;
 
          ok = reg_lookup (s, types, &lastregno);
 
          if (ok && lastregno < regno)
 
            ok = FALSE;
 
          if (!ok)
 
            break;
 
        }
 
 
 
      if (lastregno == FP && regno >= S0 && regno <= S7)
 
        {
 
          lastregno = S7;
 
          reglist |= 1 << FP;
 
        }
 
      regmask = 1 << lastregno;
 
      regmask = (regmask << 1) - 1;
 
      regmask ^= (1 << regno) - 1;
 
      reglist |= regmask;
 
 
 
      s_endlist = *s;
 
      if (**s != ',')
 
        break;
 
      (*s)++;
 
    }
 
 
 
  if (ok)
 
    *s = s_endlist;
 
  else
 
    *s = s_reset;
 
  if (reglistp)
 
    *reglistp = reglist;
 
  return ok && reglist != 0;
 
}
 
 
/* Return TRUE if opcode MO is valid on the currently selected ISA and
/* Return TRUE if opcode MO is valid on the currently selected ISA and
   architecture.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
   architecture.  Use is_opcode_valid_16 for MIPS16 opcodes.  */
 
 
static bfd_boolean
static bfd_boolean
is_opcode_valid (const struct mips_opcode *mo)
is_opcode_valid (const struct mips_opcode *mo)
Line 1851... Line 2206...
    isa |= INSN_MT;
    isa |= INSN_MT;
  if (mips_opts.ase_mips3d)
  if (mips_opts.ase_mips3d)
    isa |= INSN_MIPS3D;
    isa |= INSN_MIPS3D;
  if (mips_opts.ase_smartmips)
  if (mips_opts.ase_smartmips)
    isa |= INSN_SMARTMIPS;
    isa |= INSN_SMARTMIPS;
 
  if (mips_opts.ase_mcu)
 
    isa |= INSN_MCU;
 
 
  /* Don't accept instructions based on the ISA if the CPU does not implement
  /* Don't accept instructions based on the ISA if the CPU does not implement
     all the coprocessor insns. */
     all the coprocessor insns. */
  if (NO_ISA_COP (mips_opts.arch)
  if (NO_ISA_COP (mips_opts.arch)
      && COP_INSN (mo->pinfo))
      && COP_INSN (mo->pinfo))
Line 1893... Line 2250...
is_opcode_valid_16 (const struct mips_opcode *mo)
is_opcode_valid_16 (const struct mips_opcode *mo)
{
{
  return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
  return OPCODE_IS_MEMBER (mo, mips_opts.isa, mips_opts.arch) ? TRUE : FALSE;
}
}
 
 
 
/* Return TRUE if the size of the microMIPS opcode MO matches one
 
   explicitly requested.  Always TRUE in the standard MIPS mode.  */
 
 
 
static bfd_boolean
 
is_size_valid (const struct mips_opcode *mo)
 
{
 
  if (!mips_opts.micromips)
 
    return TRUE;
 
 
 
  if (!forced_insn_length)
 
    return TRUE;
 
  if (mo->pinfo == INSN_MACRO)
 
    return FALSE;
 
  return forced_insn_length == micromips_insn_length (mo);
 
}
 
 
 
/* Return TRUE if the microMIPS opcode MO is valid for the delay slot
 
   of the preceding instruction.  Always TRUE in the standard MIPS mode.  */
 
 
 
static bfd_boolean
 
is_delay_slot_valid (const struct mips_opcode *mo)
 
{
 
  if (!mips_opts.micromips)
 
    return TRUE;
 
 
 
  if (mo->pinfo == INSN_MACRO)
 
    return TRUE;
 
  if ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
 
      && micromips_insn_length (mo) != 4)
 
    return FALSE;
 
  if ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0
 
      && micromips_insn_length (mo) != 2)
 
    return FALSE;
 
 
 
  return TRUE;
 
}
 
 
/* This function is called once, at assembler startup time.  It should set up
/* This function is called once, at assembler startup time.  It should set up
   all the tables, etc. that the MD part of the assembler will need.  */
   all the tables, etc. that the MD part of the assembler will need.  */
 
 
void
void
md_begin (void)
md_begin (void)
Line 1978... Line 2372...
        }
        }
      while (i < bfd_mips16_num_opcodes
      while (i < bfd_mips16_num_opcodes
             && strcmp (mips16_opcodes[i].name, name) == 0);
             && strcmp (mips16_opcodes[i].name, name) == 0);
    }
    }
 
 
 
  micromips_op_hash = hash_new ();
 
 
 
  i = 0;
 
  while (i < bfd_micromips_num_opcodes)
 
    {
 
      const char *name = micromips_opcodes[i].name;
 
 
 
      retval = hash_insert (micromips_op_hash, name,
 
                            (void *) &micromips_opcodes[i]);
 
      if (retval != NULL)
 
        as_fatal (_("internal: can't hash `%s': %s"),
 
                  micromips_opcodes[i].name, retval);
 
      do
 
        if (micromips_opcodes[i].pinfo != INSN_MACRO)
 
          {
 
            struct mips_cl_insn *micromips_nop_insn;
 
 
 
            if (!validate_micromips_insn (&micromips_opcodes[i]))
 
              broken = 1;
 
 
 
            if (micromips_insn_length (micromips_opcodes + i) == 2)
 
              micromips_nop_insn = &micromips_nop16_insn;
 
            else if (micromips_insn_length (micromips_opcodes + i) == 4)
 
              micromips_nop_insn = &micromips_nop32_insn;
 
            else
 
              continue;
 
 
 
            if (micromips_nop_insn->insn_mo == NULL
 
                && strcmp (name, "nop") == 0)
 
              {
 
                create_insn (micromips_nop_insn, micromips_opcodes + i);
 
                micromips_nop_insn->fixed_p = 1;
 
              }
 
          }
 
      while (++i < bfd_micromips_num_opcodes
 
             && strcmp (micromips_opcodes[i].name, name) == 0);
 
    }
 
 
  if (broken)
  if (broken)
    as_fatal (_("Broken assembler.  No assembly attempted."));
    as_fatal (_("Broken assembler.  No assembly attempted."));
 
 
  /* We add all the general register names to the symbol table.  This
  /* We add all the general register names to the symbol table.  This
     helps us detect invalid uses of them.  */
     helps us detect invalid uses of them.  */
Line 2109... Line 2541...
}
}
 
 
void
void
md_mips_end (void)
md_mips_end (void)
{
{
 
  mips_emit_delays ();
  if (! ECOFF_DEBUGGING)
  if (! ECOFF_DEBUGGING)
    md_obj_end ();
    md_obj_end ();
}
}
 
 
void
void
Line 2157... Line 2590...
      macro_end ();
      macro_end ();
    }
    }
  else
  else
    {
    {
      if (imm_expr.X_op != O_absent)
      if (imm_expr.X_op != O_absent)
        append_insn (&insn, &imm_expr, imm_reloc);
        append_insn (&insn, &imm_expr, imm_reloc, FALSE);
      else if (offset_expr.X_op != O_absent)
      else if (offset_expr.X_op != O_absent)
        append_insn (&insn, &offset_expr, offset_reloc);
        append_insn (&insn, &offset_expr, offset_reloc, FALSE);
      else
      else
        append_insn (&insn, NULL, unused_reloc);
        append_insn (&insn, NULL, unused_reloc, FALSE);
    }
    }
}
}
 
 
/* Convenience functions for abstracting away the differences between
/* Convenience functions for abstracting away the differences between
   MIPS16 and non-MIPS16 relocations.  */
   MIPS16 and non-MIPS16 relocations.  */
Line 2188... Line 2621...
      return FALSE;
      return FALSE;
    }
    }
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
 
micromips_reloc_p (bfd_reloc_code_real_type reloc)
 
{
 
  switch (reloc)
 
    {
 
    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_GPREL16:
 
    case BFD_RELOC_MICROMIPS_JMP:
 
    case BFD_RELOC_MICROMIPS_HI16:
 
    case BFD_RELOC_MICROMIPS_HI16_S:
 
    case BFD_RELOC_MICROMIPS_LO16:
 
    case BFD_RELOC_MICROMIPS_LITERAL:
 
    case BFD_RELOC_MICROMIPS_GOT16:
 
    case BFD_RELOC_MICROMIPS_CALL16:
 
    case BFD_RELOC_MICROMIPS_GOT_HI16:
 
    case BFD_RELOC_MICROMIPS_GOT_LO16:
 
    case BFD_RELOC_MICROMIPS_CALL_HI16:
 
    case BFD_RELOC_MICROMIPS_CALL_LO16:
 
    case BFD_RELOC_MICROMIPS_SUB:
 
    case BFD_RELOC_MICROMIPS_GOT_PAGE:
 
    case BFD_RELOC_MICROMIPS_GOT_OFST:
 
    case BFD_RELOC_MICROMIPS_GOT_DISP:
 
    case BFD_RELOC_MICROMIPS_HIGHEST:
 
    case BFD_RELOC_MICROMIPS_HIGHER:
 
    case BFD_RELOC_MICROMIPS_SCN_DISP:
 
    case BFD_RELOC_MICROMIPS_JALR:
 
      return TRUE;
 
 
 
    default:
 
      return FALSE;
 
    }
 
}
 
 
 
static inline bfd_boolean
 
jmp_reloc_p (bfd_reloc_code_real_type reloc)
 
{
 
  return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP;
 
}
 
 
 
static inline bfd_boolean
got16_reloc_p (bfd_reloc_code_real_type reloc)
got16_reloc_p (bfd_reloc_code_real_type reloc)
{
{
  return reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16;
  return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
 
          || reloc == BFD_RELOC_MICROMIPS_GOT16);
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
hi16_reloc_p (bfd_reloc_code_real_type reloc)
hi16_reloc_p (bfd_reloc_code_real_type reloc)
{
{
  return reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S;
  return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
 
          || reloc == BFD_RELOC_MICROMIPS_HI16_S);
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
lo16_reloc_p (bfd_reloc_code_real_type reloc)
lo16_reloc_p (bfd_reloc_code_real_type reloc)
{
{
  return reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16;
  return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
 
          || reloc == BFD_RELOC_MICROMIPS_LO16);
 
}
 
 
 
static inline bfd_boolean
 
jalr_reloc_p (bfd_reloc_code_real_type reloc)
 
{
 
  return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
}
}
 
 
/* Return true if the given relocation might need a matching %lo().
/* Return true if the given relocation might need a matching %lo().
   This is only "might" because SVR4 R_MIPS_GOT16 relocations only
   This is only "might" because SVR4 R_MIPS_GOT16 relocations only
   need a matching %lo() when applied to local symbols.  */
   need a matching %lo() when applied to local symbols.  */
Line 2225... Line 2708...
   reloc_needs_lo_p.  */
   reloc_needs_lo_p.  */
 
 
static inline bfd_reloc_code_real_type
static inline bfd_reloc_code_real_type
matching_lo_reloc (bfd_reloc_code_real_type reloc)
matching_lo_reloc (bfd_reloc_code_real_type reloc)
{
{
  return mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16 : BFD_RELOC_LO16;
  return (mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16
 
          : (micromips_reloc_p (reloc) ? BFD_RELOC_MICROMIPS_LO16
 
             : BFD_RELOC_LO16));
}
}
 
 
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
   relocation.  */
   relocation.  */
 
 
Line 2240... Line 2725...
          && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
          && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
          && fixp->fx_addsy == fixp->fx_next->fx_addsy
          && fixp->fx_addsy == fixp->fx_next->fx_addsy
          && fixp->fx_offset == fixp->fx_next->fx_offset);
          && fixp->fx_offset == fixp->fx_next->fx_offset);
}
}
 
 
/* See whether instruction IP reads register REG.  CLASS is the type
 
   of register.  */
 
 
 
static int
 
insn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
 
               enum mips_regclass regclass)
 
{
 
  if (regclass == MIPS16_REG)
 
    {
 
      gas_assert (mips_opts.mips16);
 
      reg = mips16_to_32_reg_map[reg];
 
      regclass = MIPS_GR_REG;
 
    }
 
 
 
  /* Don't report on general register ZERO, since it never changes.  */
 
  if (regclass == MIPS_GR_REG && reg == ZERO)
 
    return 0;
 
 
 
  if (regclass == MIPS_FP_REG)
 
    {
 
      gas_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;
 
      if ((ip->insn_mo->pinfo2 & INSN2_READ_FPR_Z)
 
          && ((EXTRACT_OPERAND (FZ, *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;
 
      if ((ip->insn_mo->pinfo2 & INSN2_READ_GPR_D)
 
          && EXTRACT_OPERAND (RD, *ip) == reg)
 
        return 1;
 
      if ((ip->insn_mo->pinfo2 & INSN2_READ_GPR_Z)
 
          && EXTRACT_OPERAND (RZ, *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;
 
}
 
 
 
/* This function returns true if modifying a register requires a
/* This function returns true if modifying a register requires a
   delay.  */
   delay.  */
 
 
static int
static int
reg_needs_delay (unsigned int reg)
reg_needs_delay (unsigned int reg)
Line 2341... Line 2744...
    {
    {
      /* A load from a coprocessor or from memory.  All load delays
      /* A load from a coprocessor or from memory.  All load delays
         delay the use of general register rt for one instruction.  */
         delay the use of general register rt for one instruction.  */
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      know (prev_pinfo & INSN_WRITE_GPR_T);
      know (prev_pinfo & INSN_WRITE_GPR_T);
      if (reg == EXTRACT_OPERAND (RT, history[0]))
      if (reg == EXTRACT_OPERAND (mips_opts.micromips, RT, history[0]))
        return 1;
        return 1;
    }
    }
 
 
  return 0;
  return 0;
}
}
Line 2362... Line 2765...
  for (l = si->label_list; l != NULL; l = l->next)
  for (l = si->label_list; l != NULL; l = l->next)
    {
    {
      gas_assert (S_GET_SEGMENT (l->label) == now_seg);
      gas_assert (S_GET_SEGMENT (l->label) == now_seg);
      symbol_set_frag (l->label, frag_now);
      symbol_set_frag (l->label, frag_now);
      val = (valueT) frag_now_fix ();
      val = (valueT) frag_now_fix ();
      /* mips16 text labels are stored as odd.  */
      /* MIPS16/microMIPS text labels are stored as odd.  */
      if (mips_opts.mips16)
      if (HAVE_CODE_COMPRESSION)
        ++val;
        ++val;
      S_SET_VALUE (l->label, val);
      S_SET_VALUE (l->label, val);
    }
    }
}
}
 
 
Line 2391... Line 2794...
#endif
#endif
    }
    }
  return linkonce;
  return linkonce;
}
}
 
 
/* Mark instruction labels in mips16 mode.  This permits the linker to
/* Mark instruction labels in MIPS16/microMIPS mode.  This permits the
   handle them specially, such as generating jalx instructions when
   linker to handle them specially, such as generating jalx instructions
   needed.  We also make them odd for the duration of the assembly, in
   when needed.  We also make them odd for the duration of the assembly,
   order to generate the right sort of code.  We will make them even
   in order to generate the right sort of code.  We will make them even
   in the adjust_symtab routine, while leaving them marked.  This is
   in the adjust_symtab routine, while leaving them marked.  This is
   convenient for the debugger and the disassembler.  The linker knows
   convenient for the debugger and the disassembler.  The linker knows
   to make them odd again.  */
   to make them odd again.  */
 
 
static void
static void
mips16_mark_labels (void)
mips_compressed_mark_labels (void)
{
{
  segment_info_type *si = seg_info (now_seg);
  segment_info_type *si = seg_info (now_seg);
  struct insn_label_list *l;
  struct insn_label_list *l;
 
 
  if (!mips_opts.mips16)
  gas_assert (HAVE_CODE_COMPRESSION);
    return;
 
 
 
  for (l = si->label_list; l != NULL; l = l->next)
  for (l = si->label_list; l != NULL; l = l->next)
   {
   {
      symbolS *label = l->label;
      symbolS *label = l->label;
 
 
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
      if (IS_ELF)
      if (IS_ELF)
 
        {
 
          if (mips_opts.mips16)
        S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
        S_SET_OTHER (label, ELF_ST_SET_MIPS16 (S_GET_OTHER (label)));
 
          else
 
            S_SET_OTHER (label, ELF_ST_SET_MICROMIPS (S_GET_OTHER (label)));
 
        }
#endif
#endif
      if ((S_GET_VALUE (label) & 1) == 0
      if ((S_GET_VALUE (label) & 1) == 0
        /* Don't adjust the address if the label is global or weak, or
        /* Don't adjust the address if the label is global or weak, or
           in a link-once section, since we'll be emitting symbol reloc
           in a link-once section, since we'll be emitting symbol reloc
           references to it which will be patched up by the linker, and
           references to it which will be patched up by the linker, and
           the final value of the symbol may or may not be MIPS16.  */
           the final value of the symbol may or may not be MIPS16/microMIPS.  */
          && ! S_IS_WEAK (label)
          && ! S_IS_WEAK (label)
          && ! S_IS_EXTERNAL (label)
          && ! S_IS_EXTERNAL (label)
          && ! s_is_linkonce (label, now_seg))
          && ! s_is_linkonce (label, now_seg))
        S_SET_VALUE (label, S_GET_VALUE (label) | 1);
        S_SET_VALUE (label, S_GET_VALUE (label) | 1);
    }
    }
Line 2474... Line 2881...
  gas_assert (mips_relax.sequence == 2);
  gas_assert (mips_relax.sequence == 2);
  relax_close_frag ();
  relax_close_frag ();
  mips_relax.sequence = 0;
  mips_relax.sequence = 0;
}
}
 
 
/* Classify an instruction according to the FIX_VR4120_* enumeration.
/* Return true if IP is a delayed branch or jump.  */
   Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
 
   by VR4120 errata.  */
 
 
 
static unsigned int
static inline bfd_boolean
classify_vr4120_insn (const char *name)
delayed_branch_p (const struct mips_cl_insn *ip)
{
{
  if (strncmp (name, "macc", 4) == 0)
  return (ip->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
    return FIX_VR4120_MACC;
                                | INSN_COND_BRANCH_DELAY
  if (strncmp (name, "dmacc", 5) == 0)
                                | INSN_COND_BRANCH_LIKELY)) != 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;
 
}
}
 
 
#define INSN_ERET  0x42000018
/* Return true if IP is a compact branch or jump.  */
#define INSN_DERET 0x4200001f
 
 
static inline bfd_boolean
/* Return the number of instructions that must separate INSN1 and INSN2,
compact_branch_p (const struct mips_cl_insn *ip)
   where INSN1 is the earlier instruction.  Return the worst-case value
{
   for any INSN2 if INSN2 is null.  */
  if (mips_opts.mips16)
 
    return (ip->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
 
                                  | MIPS16_INSN_COND_BRANCH)) != 0;
 
  else
 
    return (ip->insn_mo->pinfo2 & (INSN2_UNCOND_BRANCH
 
                                   | INSN2_COND_BRANCH)) != 0;
 
}
 
 
 
/* Return true if IP is an unconditional branch or jump.  */
 
 
 
static inline bfd_boolean
 
uncond_branch_p (const struct mips_cl_insn *ip)
 
{
 
  return ((ip->insn_mo->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0
 
          || (mips_opts.mips16
 
              ? (ip->insn_mo->pinfo & MIPS16_INSN_UNCOND_BRANCH) != 0
 
              : (ip->insn_mo->pinfo2 & INSN2_UNCOND_BRANCH) != 0));
 
}
 
 
 
/* Return true if IP is a branch-likely instruction.  */
 
 
 
static inline bfd_boolean
 
branch_likely_p (const struct mips_cl_insn *ip)
 
{
 
  return (ip->insn_mo->pinfo & INSN_COND_BRANCH_LIKELY) != 0;
 
}
 
 
 
/* Return the type of nop that should be used to fill the delay slot
 
   of delayed branch IP.  */
 
 
 
static struct mips_cl_insn *
 
get_delay_slot_nop (const struct mips_cl_insn *ip)
 
{
 
  if (mips_opts.micromips
 
      && (ip->insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
 
    return &micromips_nop32_insn;
 
  return NOP_INSN;
 
}
 
 
 
/* Return the mask of core registers that IP reads or writes.  */
 
 
 
static unsigned int
 
gpr_mod_mask (const struct mips_cl_insn *ip)
 
{
 
  unsigned long pinfo2;
 
  unsigned int mask;
 
 
 
  mask = 0;
 
  pinfo2 = ip->insn_mo->pinfo2;
 
  if (mips_opts.micromips)
 
    {
 
      if (pinfo2 & INSN2_MOD_GPR_MD)
 
        mask |= 1 << micromips_to_32_reg_d_map[EXTRACT_OPERAND (1, MD, *ip)];
 
      if (pinfo2 & INSN2_MOD_GPR_MF)
 
        mask |= 1 << micromips_to_32_reg_f_map[EXTRACT_OPERAND (1, MF, *ip)];
 
      if (pinfo2 & INSN2_MOD_SP)
 
        mask |= 1 << SP;
 
    }
 
  return mask;
 
}
 
 
 
/* Return the mask of core registers that IP reads.  */
 
 
 
static unsigned int
 
gpr_read_mask (const struct mips_cl_insn *ip)
 
{
 
  unsigned long pinfo, pinfo2;
 
  unsigned int mask;
 
 
 
  mask = gpr_mod_mask (ip);
 
  pinfo = ip->insn_mo->pinfo;
 
  pinfo2 = ip->insn_mo->pinfo2;
 
  if (mips_opts.mips16)
 
    {
 
      if (pinfo & MIPS16_INSN_READ_X)
 
        mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
 
      if (pinfo & MIPS16_INSN_READ_Y)
 
        mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
 
      if (pinfo & MIPS16_INSN_READ_T)
 
        mask |= 1 << TREG;
 
      if (pinfo & MIPS16_INSN_READ_SP)
 
        mask |= 1 << SP;
 
      if (pinfo & MIPS16_INSN_READ_31)
 
        mask |= 1 << RA;
 
      if (pinfo & MIPS16_INSN_READ_Z)
 
        mask |= 1 << (mips16_to_32_reg_map
 
                      [MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]);
 
      if (pinfo & MIPS16_INSN_READ_GPR_X)
 
        mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
 
    }
 
  else
 
    {
 
      if (pinfo2 & INSN2_READ_GPR_D)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
 
      if (pinfo & INSN_READ_GPR_T)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
 
      if (pinfo & INSN_READ_GPR_S)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
 
      if (pinfo2 & INSN2_READ_GP)
 
        mask |= 1 << GP;
 
      if (pinfo2 & INSN2_READ_GPR_31)
 
        mask |= 1 << RA;
 
      if (pinfo2 & INSN2_READ_GPR_Z)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
 
    }
 
  if (mips_opts.micromips)
 
    {
 
      if (pinfo2 & INSN2_READ_GPR_MC)
 
        mask |= 1 << micromips_to_32_reg_c_map[EXTRACT_OPERAND (1, MC, *ip)];
 
      if (pinfo2 & INSN2_READ_GPR_ME)
 
        mask |= 1 << micromips_to_32_reg_e_map[EXTRACT_OPERAND (1, ME, *ip)];
 
      if (pinfo2 & INSN2_READ_GPR_MG)
 
        mask |= 1 << micromips_to_32_reg_g_map[EXTRACT_OPERAND (1, MG, *ip)];
 
      if (pinfo2 & INSN2_READ_GPR_MJ)
 
        mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
 
      if (pinfo2 & INSN2_READ_GPR_MMN)
 
        {
 
          mask |= 1 << micromips_to_32_reg_m_map[EXTRACT_OPERAND (1, MM, *ip)];
 
          mask |= 1 << micromips_to_32_reg_n_map[EXTRACT_OPERAND (1, MN, *ip)];
 
        }
 
      if (pinfo2 & INSN2_READ_GPR_MP)
 
        mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
 
      if (pinfo2 & INSN2_READ_GPR_MQ)
 
        mask |= 1 << micromips_to_32_reg_q_map[EXTRACT_OPERAND (1, MQ, *ip)];
 
    }
 
  /* Don't include register 0.  */
 
  return mask & ~1;
 
}
 
 
 
/* Return the mask of core registers that IP writes.  */
 
 
 
static unsigned int
 
gpr_write_mask (const struct mips_cl_insn *ip)
 
{
 
  unsigned long pinfo, pinfo2;
 
  unsigned int mask;
 
 
 
  mask = gpr_mod_mask (ip);
 
  pinfo = ip->insn_mo->pinfo;
 
  pinfo2 = ip->insn_mo->pinfo2;
 
  if (mips_opts.mips16)
 
    {
 
      if (pinfo & MIPS16_INSN_WRITE_X)
 
        mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)];
 
      if (pinfo & MIPS16_INSN_WRITE_Y)
 
        mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)];
 
      if (pinfo & MIPS16_INSN_WRITE_Z)
 
        mask |= 1 << mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RZ, *ip)];
 
      if (pinfo & MIPS16_INSN_WRITE_T)
 
        mask |= 1 << TREG;
 
      if (pinfo & MIPS16_INSN_WRITE_SP)
 
        mask |= 1 << SP;
 
      if (pinfo & MIPS16_INSN_WRITE_31)
 
        mask |= 1 << RA;
 
      if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
 
        mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
 
    }
 
  else
 
    {
 
      if (pinfo & INSN_WRITE_GPR_D)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
 
      if (pinfo & INSN_WRITE_GPR_T)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
 
      if (pinfo & INSN_WRITE_GPR_S)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
 
      if (pinfo & INSN_WRITE_GPR_31)
 
        mask |= 1 << RA;
 
      if (pinfo2 & INSN2_WRITE_GPR_Z)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
 
    }
 
  if (mips_opts.micromips)
 
    {
 
      if (pinfo2 & INSN2_WRITE_GPR_MB)
 
        mask |= 1 << micromips_to_32_reg_b_map[EXTRACT_OPERAND (1, MB, *ip)];
 
      if (pinfo2 & INSN2_WRITE_GPR_MHI)
 
        {
 
          mask |= 1 << micromips_to_32_reg_h_map[EXTRACT_OPERAND (1, MH, *ip)];
 
          mask |= 1 << micromips_to_32_reg_i_map[EXTRACT_OPERAND (1, MI, *ip)];
 
        }
 
      if (pinfo2 & INSN2_WRITE_GPR_MJ)
 
        mask |= 1 << EXTRACT_OPERAND (1, MJ, *ip);
 
      if (pinfo2 & INSN2_WRITE_GPR_MP)
 
        mask |= 1 << EXTRACT_OPERAND (1, MP, *ip);
 
    }
 
  /* Don't include register 0.  */
 
  return mask & ~1;
 
}
 
 
 
/* Return the mask of floating-point registers that IP reads.  */
 
 
 
static unsigned int
 
fpr_read_mask (const struct mips_cl_insn *ip)
 
{
 
  unsigned long pinfo, pinfo2;
 
  unsigned int mask;
 
 
 
  mask = 0;
 
  pinfo = ip->insn_mo->pinfo;
 
  pinfo2 = ip->insn_mo->pinfo2;
 
  if (!mips_opts.mips16)
 
    {
 
      if (pinfo2 & INSN2_READ_FPR_D)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
 
      if (pinfo & INSN_READ_FPR_S)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
 
      if (pinfo & INSN_READ_FPR_T)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FT, *ip);
 
      if (pinfo & INSN_READ_FPR_R)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FR, *ip);
 
      if (pinfo2 & INSN2_READ_FPR_Z)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FZ, *ip);
 
    }
 
  /* Conservatively treat all operands to an FP_D instruction are doubles.
 
     (This is overly pessimistic for things like cvt.d.s.)  */
 
  if (HAVE_32BIT_FPRS && (pinfo & FP_D))
 
    mask |= mask << 1;
 
  return mask;
 
}
 
 
 
/* Return the mask of floating-point registers that IP writes.  */
 
 
 
static unsigned int
 
fpr_write_mask (const struct mips_cl_insn *ip)
 
{
 
  unsigned long pinfo, pinfo2;
 
  unsigned int mask;
 
 
 
  mask = 0;
 
  pinfo = ip->insn_mo->pinfo;
 
  pinfo2 = ip->insn_mo->pinfo2;
 
  if (!mips_opts.mips16)
 
    {
 
      if (pinfo & INSN_WRITE_FPR_D)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
 
      if (pinfo & INSN_WRITE_FPR_S)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
 
      if (pinfo & INSN_WRITE_FPR_T)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FT, *ip);
 
      if (pinfo2 & INSN2_WRITE_FPR_Z)
 
        mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FZ, *ip);
 
    }
 
  /* Conservatively treat all operands to an FP_D instruction are doubles.
 
     (This is overly pessimistic for things like cvt.s.d.)  */
 
  if (HAVE_32BIT_FPRS && (pinfo & FP_D))
 
    mask |= mask << 1;
 
  return mask;
 
}
 
 
 
/* Classify an instruction according to the FIX_VR4120_* enumeration.
 
   Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
 
   by VR4120 errata.  */
 
 
 
static unsigned int
 
classify_vr4120_insn (const char *name)
 
{
 
  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;
 
}
 
 
 
#define INSN_ERET  0x42000018
 
#define INSN_DERET 0x4200001f
 
 
 
/* Return the number of instructions that must separate INSN1 and INSN2,
 
   where INSN1 is the earlier instruction.  Return the worst-case value
 
   for any INSN2 if INSN2 is null.  */
 
 
static unsigned int
static unsigned int
insns_between (const struct mips_cl_insn *insn1,
insns_between (const struct mips_cl_insn *insn1,
               const struct mips_cl_insn *insn2)
               const struct mips_cl_insn *insn2)
{
{
  unsigned long pinfo1, pinfo2;
  unsigned long pinfo1, pinfo2;
 
  unsigned int mask;
 
 
  /* This function needs to know which pinfo flags are set for INSN2
  /* This function needs to know which pinfo flags are set for INSN2
     and which registers INSN2 uses.  The former is stored in PINFO2 and
     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
     the latter is tested via INSN2_USES_GPR.  If INSN2 is null, PINFO2
     will have every flag set and INSN2_USES_REG will always return true.  */
     will have every flag set and INSN2_USES_GPR will always return true.  */
  pinfo1 = insn1->insn_mo->pinfo;
  pinfo1 = insn1->insn_mo->pinfo;
  pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
  pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
 
 
#define INSN2_USES_REG(REG, CLASS) \
#define INSN2_USES_GPR(REG) \
   (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
  (insn2 == NULL || (gpr_read_mask (insn2) & (1U << (REG))) != 0)
 
 
  /* For most targets, write-after-read dependencies on the HI and LO
  /* For most targets, write-after-read dependencies on the HI and LO
     registers must be separated by at least two instructions.  */
     registers must be separated by at least two instructions.  */
  if (!hilo_interlocks)
  if (!hilo_interlocks)
    {
    {
Line 2532... Line 3203...
    }
    }
 
 
  /* If we're working around r7000 errata, there must be two instructions
  /* If we're working around r7000 errata, there must be two instructions
     between an mfhi or mflo and any instruction that uses the result.  */
     between an mfhi or mflo and any instruction that uses the result.  */
  if (mips_7000_hilo_fix
  if (mips_7000_hilo_fix
 
      && !mips_opts.micromips
      && MF_HILO_INSN (pinfo1)
      && MF_HILO_INSN (pinfo1)
      && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
      && INSN2_USES_GPR (EXTRACT_OPERAND (0, RD, *insn1)))
    return 2;
    return 2;
 
 
  /* If we're working around 24K errata, one instruction is required
  /* If we're working around 24K errata, one instruction is required
     if an ERET or DERET is followed by a branch instruction.  */
     if an ERET or DERET is followed by a branch instruction.  */
  if (mips_fix_24k)
  if (mips_fix_24k && !mips_opts.micromips)
    {
    {
      if (insn1->insn_opcode == INSN_ERET
      if (insn1->insn_opcode == INSN_ERET
          || insn1->insn_opcode == INSN_DERET)
          || insn1->insn_opcode == INSN_DERET)
        {
        {
          if (insn2 == NULL
          if (insn2 == NULL
              || insn2->insn_opcode == INSN_ERET
              || insn2->insn_opcode == INSN_ERET
              || insn2->insn_opcode == INSN_DERET
              || insn2->insn_opcode == INSN_DERET
              || (insn2->insn_mo->pinfo
              || delayed_branch_p (insn2))
                  & (INSN_UNCOND_BRANCH_DELAY
 
                     | INSN_COND_BRANCH_DELAY
 
                     | INSN_COND_BRANCH_LIKELY)) != 0)
 
            return 1;
            return 1;
        }
        }
    }
    }
 
 
  /* If working around VR4120 errata, check for combinations that need
  /* If working around VR4120 errata, check for combinations that need
     a single intervening instruction.  */
     a single intervening instruction.  */
  if (mips_fix_vr4120)
  if (mips_fix_vr4120 && !mips_opts.micromips)
    {
    {
      unsigned int class1, class2;
      unsigned int class1, class2;
 
 
      class1 = classify_vr4120_insn (insn1->insn_mo->name);
      class1 = classify_vr4120_insn (insn1->insn_mo->name);
      if (class1 != NUM_FIX_VR4120_CLASSES && vr4120_conflicts[class1] != 0)
      if (class1 != NUM_FIX_VR4120_CLASSES && vr4120_conflicts[class1] != 0)
Line 2571... Line 3240...
          if (vr4120_conflicts[class1] & (1 << class2))
          if (vr4120_conflicts[class1] & (1 << class2))
            return 1;
            return 1;
        }
        }
    }
    }
 
 
  if (!mips_opts.mips16)
  if (!HAVE_CODE_COMPRESSION)
    {
    {
      /* Check for GPR or coprocessor load delays.  All such delays
      /* Check for GPR or coprocessor load delays.  All such delays
         are on the RT register.  */
         are on the RT register.  */
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
          || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
          || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
        {
        {
          know (pinfo1 & INSN_WRITE_GPR_T);
          know (pinfo1 & INSN_WRITE_GPR_T);
          if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
          if (INSN2_USES_GPR (EXTRACT_OPERAND (0, RT, *insn1)))
            return 1;
            return 1;
        }
        }
 
 
      /* Check for generic coprocessor hazards.
      /* Check for generic coprocessor hazards.
 
 
Line 2598... Line 3267...
               || (!cop_mem_interlocks && (pinfo1 & INSN_COPROC_MEMORY_DELAY)))
               || (!cop_mem_interlocks && (pinfo1 & INSN_COPROC_MEMORY_DELAY)))
        {
        {
          /* Handle cases where INSN1 writes to a known general coprocessor
          /* Handle cases where INSN1 writes to a known general coprocessor
             register.  There must be a one instruction delay before INSN2
             register.  There must be a one instruction delay before INSN2
             if INSN2 reads that register, otherwise no delay is needed.  */
             if INSN2 reads that register, otherwise no delay is needed.  */
          if (pinfo1 & INSN_WRITE_FPR_T)
          mask = fpr_write_mask (insn1);
 
          if (mask != 0)
            {
            {
              if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
              if (!insn2 || (mask & fpr_read_mask (insn2)) != 0)
                return 1;
 
            }
 
          else if (pinfo1 & INSN_WRITE_FPR_S)
 
            {
 
              if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
 
                return 1;
                return 1;
            }
            }
          else
          else
            {
            {
              /* Read-after-write dependencies on the control registers
              /* Read-after-write dependencies on the control registers
Line 2635... Line 3300...
               && (pinfo1 & INSN_WRITE_COND_CODE)
               && (pinfo1 & INSN_WRITE_COND_CODE)
               && (pinfo2 & INSN_READ_COND_CODE))
               && (pinfo2 & INSN_READ_COND_CODE))
        return 1;
        return 1;
    }
    }
 
 
#undef INSN2_USES_REG
#undef INSN2_USES_GPR
 
 
  return 0;
  return 0;
}
}
 
 
/* Return the number of nops that would be needed to work around the
/* Return the number of nops that would be needed to work around the
   VR4130 mflo/mfhi errata if instruction INSN immediately followed
   VR4130 mflo/mfhi errata if instruction INSN immediately followed
   the MAX_VR4130_NOPS instructions described by HIST.  */
   the MAX_VR4130_NOPS instructions described by HIST.  Ignore hazards
 
   that are contained within the first IGNORE instructions of HIST.  */
 
 
static int
static int
nops_for_vr4130 (const struct mips_cl_insn *hist,
nops_for_vr4130 (int ignore, const struct mips_cl_insn *hist,
                 const struct mips_cl_insn *insn)
                 const struct mips_cl_insn *insn)
{
{
  int i, j, reg;
  int i, j;
 
  unsigned int mask;
 
 
  /* Check if the instruction writes to HI or LO.  MTHI and MTLO
  /* Check if the instruction writes to HI or LO.  MTHI and MTLO
     are not affected by the errata.  */
     are not affected by the errata.  */
  if (insn != 0
  if (insn != 0
      && ((insn->insn_mo->pinfo & (INSN_WRITE_HI | INSN_WRITE_LO)) == 0
      && ((insn->insn_mo->pinfo & (INSN_WRITE_HI | INSN_WRITE_LO)) == 0
Line 2663... Line 3330...
  /* Search for the first MFLO or MFHI.  */
  /* Search for the first MFLO or MFHI.  */
  for (i = 0; i < MAX_VR4130_NOPS; i++)
  for (i = 0; i < MAX_VR4130_NOPS; i++)
    if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
    if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
      {
      {
        /* Extract the destination register.  */
        /* Extract the destination register.  */
        if (mips_opts.mips16)
        mask = gpr_write_mask (&hist[i]);
          reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, hist[i])];
 
        else
 
          reg = EXTRACT_OPERAND (RD, hist[i]);
 
 
 
        /* No nops are needed if INSN reads that register.  */
        /* No nops are needed if INSN reads that register.  */
        if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
        if (insn != NULL && (gpr_read_mask (insn) & mask) != 0)
          return 0;
          return 0;
 
 
        /* ...or if any of the intervening instructions do.  */
        /* ...or if any of the intervening instructions do.  */
        for (j = 0; j < i; j++)
        for (j = 0; j < i; j++)
          if (insn_uses_reg (&hist[j], reg, MIPS_GR_REG))
          if (gpr_read_mask (&hist[j]) & mask)
            return 0;
            return 0;
 
 
 
        if (i >= ignore)
        return MAX_VR4130_NOPS - i;
        return MAX_VR4130_NOPS - i;
      }
      }
  return 0;
  return 0;
}
}
 
 
Line 2747... Line 3412...
  stinfo->off = (insn->insn_opcode >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE;
  stinfo->off = (insn->insn_opcode >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE;
  stinfo->align_to = fix_24k_align_to (insn->insn_mo);
  stinfo->align_to = fix_24k_align_to (insn->insn_mo);
  return TRUE;
  return TRUE;
}
}
 
 
/* 24K Errata: Lost Data on Stores During Refill.
/* Return the number of nops that would be needed to work around the 24k
 
   "lost data on stores during refill" errata if instruction INSN
 
   immediately followed the 2 instructions described by HIST.
 
   Ignore hazards that are contained within the first IGNORE
 
   instructions of HIST.
 
 
  Problem: The FSB (fetch store buffer) acts as an intermediate buffer
  Problem: The FSB (fetch store buffer) acts as an intermediate buffer
  for the data cache refills and store data. The following describes
  for the data cache refills and store data. The following describes
  the scenario where the store data could be lost.
  the scenario where the store data could be lost.
 
 
Line 2787... Line 3456...
  * Run the data cache in write-through mode.
  * Run the data cache in write-through mode.
  * Insert a non-store instruction between
  * Insert a non-store instruction between
    Store A and Store B or Store B and Store C.  */
    Store A and Store B or Store B and Store C.  */
 
 
static int
static int
nops_for_24k (const struct mips_cl_insn *hist,
nops_for_24k (int ignore, const struct mips_cl_insn *hist,
              const struct mips_cl_insn *insn)
              const struct mips_cl_insn *insn)
{
{
  struct fix_24k_store_info pos[3];
  struct fix_24k_store_info pos[3];
  int align, i, base_offset;
  int align, i, base_offset;
 
 
  /* If INSN is definitely not a store, there's nothing to worry about.  */
  if (ignore >= 2)
  if (insn && (insn->insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
 
    return 0;
    return 0;
 
 
  /* Likewise, the previous instruction wasn't a store.  */
  /* If the previous instruction wasn't a store, there's nothing to
 
     worry about.  */
  if ((hist[0].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
  if ((hist[0].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
    return 0;
    return 0;
 
 
  /* If we don't know what came before, assume the worst.  */
  /* If the instructions after the previous one are unknown, we have
  if (hist[1].frag == NULL)
     to assume the worst.  */
 
  if (!insn)
    return 1;
    return 1;
 
 
  /* If the instruction was not a store, there's nothing to worry about.  */
  /* Check whether we are dealing with three consecutive stores.  */
  if ((hist[1].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
  if ((insn->insn_mo->pinfo & INSN_STORE_MEMORY) == 0
 
      || (hist[1].insn_mo->pinfo & INSN_STORE_MEMORY) == 0)
    return 0;
    return 0;
 
 
  /* If we don't know the relationship between the store addresses,
  /* If we don't know the relationship between the store addresses,
     assume the worst.  */
     assume the worst.  */
  if (insn == NULL
  if (!BASE_REG_EQ (insn->insn_opcode, hist[0].insn_opcode)
      || !BASE_REG_EQ (insn->insn_opcode, hist[0].insn_opcode)
 
      || !BASE_REG_EQ (insn->insn_opcode, hist[1].insn_opcode))
      || !BASE_REG_EQ (insn->insn_opcode, hist[1].insn_opcode))
    return 1;
    return 1;
 
 
  if (!fix_24k_record_store_info (&pos[0], insn)
  if (!fix_24k_record_store_info (&pos[0], insn)
      || !fix_24k_record_store_info (&pos[1], &hist[0])
      || !fix_24k_record_store_info (&pos[1], &hist[0])
Line 2867... Line 3537...
  return 1;
  return 1;
}
}
 
 
/* Return the number of nops that would be needed if instruction INSN
/* Return the number of nops that would be needed if instruction INSN
   immediately followed the MAX_NOPS instructions given by HIST,
   immediately followed the MAX_NOPS instructions given by HIST,
   where HIST[0] is the most recent instruction.  If INSN is null,
   where HIST[0] is the most recent instruction.  Ignore hazards
   return the worse-case number of nops for any instruction.  */
   between INSN and the first IGNORE instructions in HIST.
 
 
 
   If INSN is null, return the worse-case number of nops for any
 
   instruction.  */
 
 
static int
static int
nops_for_insn (const struct mips_cl_insn *hist,
nops_for_insn (int ignore, const struct mips_cl_insn *hist,
               const struct mips_cl_insn *insn)
               const struct mips_cl_insn *insn)
{
{
  int i, nops, tmp_nops;
  int i, nops, tmp_nops;
 
 
  nops = 0;
  nops = 0;
  for (i = 0; i < MAX_DELAY_NOPS; i++)
  for (i = ignore; i < MAX_DELAY_NOPS; i++)
    {
    {
      tmp_nops = insns_between (hist + i, insn) - i;
      tmp_nops = insns_between (hist + i, insn) - i;
      if (tmp_nops > nops)
      if (tmp_nops > nops)
        nops = tmp_nops;
        nops = tmp_nops;
    }
    }
 
 
  if (mips_fix_vr4130)
  if (mips_fix_vr4130 && !mips_opts.micromips)
    {
    {
      tmp_nops = nops_for_vr4130 (hist, insn);
      tmp_nops = nops_for_vr4130 (ignore, hist, insn);
      if (tmp_nops > nops)
      if (tmp_nops > nops)
        nops = tmp_nops;
        nops = tmp_nops;
    }
    }
 
 
  if (mips_fix_24k)
  if (mips_fix_24k && !mips_opts.micromips)
    {
    {
      tmp_nops = nops_for_24k (hist, insn);
      tmp_nops = nops_for_24k (ignore, hist, insn);
      if (tmp_nops > nops)
      if (tmp_nops > nops)
        nops = tmp_nops;
        nops = tmp_nops;
    }
    }
 
 
  return nops;
  return nops;
}
}
 
 
/* The variable arguments provide NUM_INSNS extra instructions that
/* The variable arguments provide NUM_INSNS extra instructions that
   might be added to HIST.  Return the largest number of nops that
   might be added to HIST.  Return the largest number of nops that
   would be needed after the extended sequence.  */
   would be needed after the extended sequence, ignoring hazards
 
   in the first IGNORE instructions.  */
 
 
static int
static int
nops_for_sequence (int num_insns, const struct mips_cl_insn *hist, ...)
nops_for_sequence (int num_insns, int ignore,
 
                   const struct mips_cl_insn *hist, ...)
{
{
  va_list args;
  va_list args;
  struct mips_cl_insn buffer[MAX_NOPS];
  struct mips_cl_insn buffer[MAX_NOPS];
  struct mips_cl_insn *cursor;
  struct mips_cl_insn *cursor;
  int nops;
  int nops;
Line 2919... Line 3594...
  cursor = buffer + num_insns;
  cursor = buffer + num_insns;
  memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
  memcpy (cursor, hist, (MAX_NOPS - num_insns) * sizeof (*cursor));
  while (cursor > buffer)
  while (cursor > buffer)
    *--cursor = *va_arg (args, const struct mips_cl_insn *);
    *--cursor = *va_arg (args, const struct mips_cl_insn *);
 
 
  nops = nops_for_insn (buffer, NULL);
  nops = nops_for_insn (ignore, buffer, NULL);
  va_end (args);
  va_end (args);
  return nops;
  return nops;
}
}
 
 
/* Like nops_for_insn, but if INSN is a branch, take into account the
/* Like nops_for_insn, but if INSN is a branch, take into account the
   worst-case delay for the branch target.  */
   worst-case delay for the branch target.  */
 
 
static int
static int
nops_for_insn_or_target (const struct mips_cl_insn *hist,
nops_for_insn_or_target (int ignore, const struct mips_cl_insn *hist,
                         const struct mips_cl_insn *insn)
                         const struct mips_cl_insn *insn)
{
{
  int nops, tmp_nops;
  int nops, tmp_nops;
 
 
  nops = nops_for_insn (hist, insn);
  nops = nops_for_insn (ignore, hist, insn);
  if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
  if (delayed_branch_p (insn))
                              | INSN_COND_BRANCH_DELAY
 
                              | INSN_COND_BRANCH_LIKELY))
 
    {
    {
      tmp_nops = nops_for_sequence (2, hist, insn, NOP_INSN);
      tmp_nops = nops_for_sequence (2, ignore ? ignore + 2 : 0,
 
                                    hist, insn, get_delay_slot_nop (insn));
      if (tmp_nops > nops)
      if (tmp_nops > nops)
        nops = tmp_nops;
        nops = tmp_nops;
    }
    }
  else if (mips_opts.mips16
  else if (compact_branch_p (insn))
           && (insn->insn_mo->pinfo & (MIPS16_INSN_UNCOND_BRANCH
 
                                       | MIPS16_INSN_COND_BRANCH)))
 
    {
    {
      tmp_nops = nops_for_sequence (1, hist, insn);
      tmp_nops = nops_for_sequence (1, ignore ? ignore + 1 : 0, hist, insn);
      if (tmp_nops > nops)
      if (tmp_nops > nops)
        nops = tmp_nops;
        nops = tmp_nops;
    }
    }
  return nops;
  return nops;
}
}
Line 2958... Line 3630...
/* Fix NOP issue: Replace nops by "or at,at,zero".  */
/* Fix NOP issue: Replace nops by "or at,at,zero".  */
 
 
static void
static void
fix_loongson2f_nop (struct mips_cl_insn * ip)
fix_loongson2f_nop (struct mips_cl_insn * ip)
{
{
 
  gas_assert (!HAVE_CODE_COMPRESSION);
  if (strcmp (ip->insn_mo->name, "nop") == 0)
  if (strcmp (ip->insn_mo->name, "nop") == 0)
    ip->insn_opcode = LOONGSON2F_NOP_INSN;
    ip->insn_opcode = LOONGSON2F_NOP_INSN;
}
}
 
 
/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
/* Fix Jump Issue: Eliminate instruction fetch from outside 256M region
                   jr target pc &= 'hffff_ffff_cfff_ffff.  */
                   jr target pc &= 'hffff_ffff_cfff_ffff.  */
 
 
static void
static void
fix_loongson2f_jump (struct mips_cl_insn * ip)
fix_loongson2f_jump (struct mips_cl_insn * ip)
{
{
 
  gas_assert (!HAVE_CODE_COMPRESSION);
  if (strcmp (ip->insn_mo->name, "j") == 0
  if (strcmp (ip->insn_mo->name, "j") == 0
      || strcmp (ip->insn_mo->name, "jr") == 0
      || strcmp (ip->insn_mo->name, "jr") == 0
      || strcmp (ip->insn_mo->name, "jalr") == 0)
      || strcmp (ip->insn_mo->name, "jalr") == 0)
    {
    {
      int sreg;
      int sreg;
      expressionS ep;
      expressionS ep;
 
 
      if (! mips_opts.at)
      if (! mips_opts.at)
        return;
        return;
 
 
      sreg = EXTRACT_OPERAND (RS, *ip);
      sreg = EXTRACT_OPERAND (0, RS, *ip);
      if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
      if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG)
        return;
        return;
 
 
      ep.X_op = O_constant;
      ep.X_op = O_constant;
      ep.X_add_number = 0xcfff0000;
      ep.X_add_number = 0xcfff0000;
Line 3001... Line 3675...
 
 
  if (mips_fix_loongson2f_jump)
  if (mips_fix_loongson2f_jump)
    fix_loongson2f_jump (ip);
    fix_loongson2f_jump (ip);
}
}
 
 
/* Output an instruction.  IP is the instruction information.
/* IP is a branch that has a delay slot, and we need to fill it
   ADDRESS_EXPR is an operand of the instruction to be used with
   automatically.   Return true if we can do that by swapping IP
   RELOC_TYPE.  */
   with the previous instruction.  */
 
 
static void
static bfd_boolean
append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
can_swap_branch_p (struct mips_cl_insn *ip)
             bfd_reloc_code_real_type *reloc_type)
 
{
{
  unsigned long prev_pinfo, pinfo;
  unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2;
  unsigned long prev_pinfo2, pinfo2;
  unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write;
  relax_stateT prev_insn_frag_type = 0;
 
  bfd_boolean relaxed_branch = FALSE;
 
  segment_info_type *si = seg_info (now_seg);
 
 
 
  if (mips_fix_loongson2f)
 
    fix_loongson2f (ip);
 
 
 
  /* Mark instruction labels in mips16 mode.  */
  /* -O2 and above is required for this optimization.  */
  mips16_mark_labels ();
  if (mips_optimize < 2)
 
    return FALSE;
 
 
  file_ase_mips16 |= mips_opts.mips16;
  /* If we have seen .set volatile or .set nomove, don't optimize.  */
 
  if (mips_opts.nomove)
 
    return FALSE;
 
 
  prev_pinfo = history[0].insn_mo->pinfo;
  /* We can't swap if the previous instruction's position is fixed.  */
  prev_pinfo2 = history[0].insn_mo->pinfo2;
  if (history[0].fixed_p)
  pinfo = ip->insn_mo->pinfo;
    return FALSE;
  pinfo2 = ip->insn_mo->pinfo2;
 
 
 
  if (address_expr == NULL)
  /* If the previous previous insn was in a .set noreorder, we can't
    ip->complete_p = 1;
     swap.  Actually, the MIPS assembler will swap in this situation.
  else if (*reloc_type <= BFD_RELOC_UNUSED
     However, gcc configured -with-gnu-as will generate code like
           && address_expr->X_op == O_constant)
 
    {
 
      unsigned int tmp;
 
 
 
      ip->complete_p = 1;
        .set    noreorder
      switch (*reloc_type)
        lw      $4,XXX
        {
        .set    reorder
        case BFD_RELOC_32:
        INSN
          ip->insn_opcode |= address_expr->X_add_number;
        bne     $4,$0,foo
          break;
 
 
 
        case BFD_RELOC_MIPS_HIGHEST:
     in which we can not swap the bne and INSN.  If gcc is not configured
          tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
     -with-gnu-as, it does not output the .set pseudo-ops.  */
          ip->insn_opcode |= tmp & 0xffff;
  if (history[1].noreorder_p)
          break;
    return FALSE;
 
 
        case BFD_RELOC_MIPS_HIGHER:
  /* If the previous instruction had a fixup in mips16 mode, we can not swap.
          tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
     This means that the previous instruction was a 4-byte one anyhow.  */
          ip->insn_opcode |= tmp & 0xffff;
  if (mips_opts.mips16 && history[0].fixp[0])
          break;
    return FALSE;
 
 
        case BFD_RELOC_HI16_S:
  /* If the branch is itself the target of a branch, we can not swap.
          tmp = (address_expr->X_add_number + 0x8000) >> 16;
     We cheat on this; all we check for is whether there is a label on
          ip->insn_opcode |= tmp & 0xffff;
     this instruction.  If there are any branches to anything other than
          break;
     a label, users must use .set noreorder.  */
 
  if (seg_info (now_seg)->label_list)
 
    return FALSE;
 
 
        case BFD_RELOC_HI16:
  /* If the previous instruction is in a variant frag other than this
          ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
     branch's one, we cannot do the swap.  This does not apply to
          break;
     MIPS16/microMIPS code, which uses variant frags for different
 
     purposes.  */
 
  if (!HAVE_CODE_COMPRESSION
 
      && history[0].frag
 
      && history[0].frag->fr_type == rs_machine_dependent)
 
    return FALSE;
 
 
        case BFD_RELOC_UNUSED:
  /* We do not swap with instructions that cannot architecturally
        case BFD_RELOC_LO16:
     be placed in a branch delay slot, such as SYNC or ERET.  We
        case BFD_RELOC_MIPS_GOT_DISP:
     also refrain from swapping with a trap instruction, since it
          ip->insn_opcode |= address_expr->X_add_number & 0xffff;
     complicates trap handlers to have the trap instruction be in
          break;
     a delay slot.  */
 
  prev_pinfo = history[0].insn_mo->pinfo;
 
  if (prev_pinfo & INSN_NO_DELAY_SLOT)
 
    return FALSE;
 
 
        case BFD_RELOC_MIPS_JMP:
  /* Check for conflicts between the branch and the instructions
          if ((address_expr->X_add_number & 3) != 0)
     before the candidate delay slot.  */
            as_bad (_("jump to misaligned address (0x%lx)"),
  if (nops_for_insn (0, history + 1, ip) > 0)
                    (unsigned long) address_expr->X_add_number);
    return FALSE;
          ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
 
          ip->complete_p = 0;
 
          break;
 
 
 
        case BFD_RELOC_MIPS16_JMP:
  /* Check for conflicts between the swapped sequence and the
          if ((address_expr->X_add_number & 3) != 0)
     target of the branch.  */
            as_bad (_("jump to misaligned address (0x%lx)"),
  if (nops_for_sequence (2, 0, history + 1, ip, history) > 0)
                    (unsigned long) address_expr->X_add_number);
    return FALSE;
          ip->insn_opcode |=
 
            (((address_expr->X_add_number & 0x7c0000) << 3)
 
               | ((address_expr->X_add_number & 0xf800000) >> 7)
 
               | ((address_expr->X_add_number & 0x3fffc) >> 2));
 
          ip->complete_p = 0;
 
          break;
 
 
 
        case BFD_RELOC_16_PCREL_S2:
  /* If the branch reads a register that the previous
          if ((address_expr->X_add_number & 3) != 0)
     instruction sets, we can not swap.  */
            as_bad (_("branch to misaligned address (0x%lx)"),
  gpr_read = gpr_read_mask (ip);
                    (unsigned long) address_expr->X_add_number);
  prev_gpr_write = gpr_write_mask (&history[0]);
          if (mips_relax_branch)
  if (gpr_read & prev_gpr_write)
            goto need_reloc;
    return FALSE;
          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;
 
          ip->complete_p = 0;
 
          break;
 
 
 
        default:
  /* If the branch writes a register that the previous
          internalError ();
     instruction sets, we can not swap.  */
        }
  gpr_write = gpr_write_mask (ip);
 
  if (gpr_write & prev_gpr_write)
 
    return FALSE;
 
 
 
  /* If the branch writes a register that the previous
 
     instruction reads, we can not swap.  */
 
  prev_gpr_read = gpr_read_mask (&history[0]);
 
  if (gpr_write & prev_gpr_read)
 
    return FALSE;
 
 
 
  /* If one instruction sets a condition code and the
 
     other one uses a condition code, we can not swap.  */
 
  pinfo = ip->insn_mo->pinfo;
 
  if ((pinfo & INSN_READ_COND_CODE)
 
      && (prev_pinfo & INSN_WRITE_COND_CODE))
 
    return FALSE;
 
  if ((pinfo & INSN_WRITE_COND_CODE)
 
      && (prev_pinfo & INSN_READ_COND_CODE))
 
    return FALSE;
 
 
 
  /* If the previous instruction uses the PC, we can not swap.  */
 
  prev_pinfo2 = history[0].insn_mo->pinfo2;
 
  if (mips_opts.mips16 && (prev_pinfo & MIPS16_INSN_READ_PC))
 
    return FALSE;
 
  if (mips_opts.micromips && (prev_pinfo2 & INSN2_READ_PC))
 
    return FALSE;
 
 
 
  /* If the previous instruction has an incorrect size for a fixed
 
     branch delay slot in microMIPS mode, we cannot swap.  */
 
  pinfo2 = ip->insn_mo->pinfo2;
 
  if (mips_opts.micromips
 
      && (pinfo2 & INSN2_BRANCH_DELAY_16BIT)
 
      && insn_length (history) != 2)
 
    return FALSE;
 
  if (mips_opts.micromips
 
      && (pinfo2 & INSN2_BRANCH_DELAY_32BIT)
 
      && insn_length (history) != 4)
 
    return FALSE;
 
 
 
  return TRUE;
    }
    }
 
 
  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
/* Decide how we should add IP to the instruction stream.  */
 
 
 
static enum append_method
 
get_append_method (struct mips_cl_insn *ip)
    {
    {
      /* There are a lot of optimizations we could do that we don't.
  unsigned long pinfo;
         In particular, we do not, in general, reorder instructions.
 
 
  /* The relaxed version of a macro sequence must be inherently
 
     hazard-free.  */
 
  if (mips_relax.sequence == 2)
 
    return APPEND_ADD;
 
 
 
  /* We must not dabble with instructions in a ".set norerorder" block.  */
 
  if (mips_opts.noreorder)
 
    return APPEND_ADD;
 
 
 
  /* Otherwise, it's our responsibility to fill branch delay slots.  */
 
  if (delayed_branch_p (ip))
 
    {
 
      if (!branch_likely_p (ip) && can_swap_branch_p (ip))
 
        return APPEND_SWAP;
 
 
 
      pinfo = ip->insn_mo->pinfo;
 
      if (mips_opts.mips16
 
          && ISA_SUPPORTS_MIPS16E
 
          && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31)))
 
        return APPEND_ADD_COMPACT;
 
 
 
      return APPEND_ADD_WITH_NOP;
 
    }
 
 
 
  return APPEND_ADD;
 
}
 
 
 
/* IP is a MIPS16 instruction whose opcode we have just changed.
 
   Point IP->insn_mo to the new opcode's definition.  */
 
 
 
static void
 
find_altered_mips16_opcode (struct mips_cl_insn *ip)
 
{
 
  const struct mips_opcode *mo, *end;
 
 
 
  end = &mips16_opcodes[bfd_mips16_num_opcodes];
 
  for (mo = ip->insn_mo; mo < end; mo++)
 
    if ((ip->insn_opcode & mo->mask) == mo->match)
 
      {
 
        ip->insn_mo = mo;
 
        return;
 
      }
 
  abort ();
 
}
 
 
 
/* For microMIPS macros, we need to generate a local number label
 
   as the target of branches.  */
 
#define MICROMIPS_LABEL_CHAR            '\037'
 
static unsigned long micromips_target_label;
 
static char micromips_target_name[32];
 
 
 
static char *
 
micromips_label_name (void)
 
{
 
  char *p = micromips_target_name;
 
  char symbol_name_temporary[24];
 
  unsigned long l;
 
  int i;
 
 
 
  if (*p)
 
    return p;
 
 
 
  i = 0;
 
  l = micromips_target_label;
 
#ifdef LOCAL_LABEL_PREFIX
 
  *p++ = LOCAL_LABEL_PREFIX;
 
#endif
 
  *p++ = 'L';
 
  *p++ = MICROMIPS_LABEL_CHAR;
 
  do
 
    {
 
      symbol_name_temporary[i++] = l % 10 + '0';
 
      l /= 10;
 
    }
 
  while (l != 0);
 
  while (i > 0)
 
    *p++ = symbol_name_temporary[--i];
 
  *p = '\0';
 
 
 
  return micromips_target_name;
 
}
 
 
 
static void
 
micromips_label_expr (expressionS *label_expr)
 
{
 
  label_expr->X_op = O_symbol;
 
  label_expr->X_add_symbol = symbol_find_or_make (micromips_label_name ());
 
  label_expr->X_add_number = 0;
 
}
 
 
 
static void
 
micromips_label_inc (void)
 
{
 
  micromips_target_label++;
 
  *micromips_target_name = '\0';
 
}
 
 
 
static void
 
micromips_add_label (void)
 
{
 
  symbolS *s;
 
 
 
  s = colon (micromips_label_name ());
 
  micromips_label_inc ();
 
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
 
  if (IS_ELF)
 
    S_SET_OTHER (s, ELF_ST_SET_MICROMIPS (S_GET_OTHER (s)));
 
#endif
 
}
 
 
 
/* If assembling microMIPS code, then return the microMIPS reloc
 
   corresponding to the requested one if any.  Otherwise return
 
   the reloc unchanged.  */
 
 
 
static bfd_reloc_code_real_type
 
micromips_map_reloc (bfd_reloc_code_real_type reloc)
 
{
 
  static const bfd_reloc_code_real_type relocs[][2] =
 
    {
 
      /* Keep sorted incrementally by the left-hand key.  */
 
      { BFD_RELOC_16_PCREL_S2, BFD_RELOC_MICROMIPS_16_PCREL_S1 },
 
      { BFD_RELOC_GPREL16, BFD_RELOC_MICROMIPS_GPREL16 },
 
      { BFD_RELOC_MIPS_JMP, BFD_RELOC_MICROMIPS_JMP },
 
      { BFD_RELOC_HI16, BFD_RELOC_MICROMIPS_HI16 },
 
      { BFD_RELOC_HI16_S, BFD_RELOC_MICROMIPS_HI16_S },
 
      { BFD_RELOC_LO16, BFD_RELOC_MICROMIPS_LO16 },
 
      { BFD_RELOC_MIPS_LITERAL, BFD_RELOC_MICROMIPS_LITERAL },
 
      { BFD_RELOC_MIPS_GOT16, BFD_RELOC_MICROMIPS_GOT16 },
 
      { BFD_RELOC_MIPS_CALL16, BFD_RELOC_MICROMIPS_CALL16 },
 
      { BFD_RELOC_MIPS_GOT_HI16, BFD_RELOC_MICROMIPS_GOT_HI16 },
 
      { BFD_RELOC_MIPS_GOT_LO16, BFD_RELOC_MICROMIPS_GOT_LO16 },
 
      { BFD_RELOC_MIPS_CALL_HI16, BFD_RELOC_MICROMIPS_CALL_HI16 },
 
      { BFD_RELOC_MIPS_CALL_LO16, BFD_RELOC_MICROMIPS_CALL_LO16 },
 
      { BFD_RELOC_MIPS_SUB, BFD_RELOC_MICROMIPS_SUB },
 
      { BFD_RELOC_MIPS_GOT_PAGE, BFD_RELOC_MICROMIPS_GOT_PAGE },
 
      { BFD_RELOC_MIPS_GOT_OFST, BFD_RELOC_MICROMIPS_GOT_OFST },
 
      { BFD_RELOC_MIPS_GOT_DISP, BFD_RELOC_MICROMIPS_GOT_DISP },
 
      { BFD_RELOC_MIPS_HIGHEST, BFD_RELOC_MICROMIPS_HIGHEST },
 
      { BFD_RELOC_MIPS_HIGHER, BFD_RELOC_MICROMIPS_HIGHER },
 
      { BFD_RELOC_MIPS_SCN_DISP, BFD_RELOC_MICROMIPS_SCN_DISP },
 
      { BFD_RELOC_MIPS_TLS_GD, BFD_RELOC_MICROMIPS_TLS_GD },
 
      { BFD_RELOC_MIPS_TLS_LDM, BFD_RELOC_MICROMIPS_TLS_LDM },
 
      { BFD_RELOC_MIPS_TLS_DTPREL_HI16, BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16 },
 
      { BFD_RELOC_MIPS_TLS_DTPREL_LO16, BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16 },
 
      { BFD_RELOC_MIPS_TLS_GOTTPREL, BFD_RELOC_MICROMIPS_TLS_GOTTPREL },
 
      { BFD_RELOC_MIPS_TLS_TPREL_HI16, BFD_RELOC_MICROMIPS_TLS_TPREL_HI16 },
 
      { BFD_RELOC_MIPS_TLS_TPREL_LO16, BFD_RELOC_MICROMIPS_TLS_TPREL_LO16 }
 
    };
 
  bfd_reloc_code_real_type r;
 
  size_t i;
 
 
 
  if (!mips_opts.micromips)
 
    return reloc;
 
  for (i = 0; i < ARRAY_SIZE (relocs); i++)
 
    {
 
      r = relocs[i][0];
 
      if (r > reloc)
 
        return reloc;
 
      if (r == reloc)
 
        return relocs[i][1];
 
    }
 
  return reloc;
 
}
 
 
 
/* Output an instruction.  IP is the instruction information.
 
   ADDRESS_EXPR is an operand of the instruction to be used with
 
   RELOC_TYPE.  EXPANSIONP is true if the instruction is part of
 
   a macro expansion.  */
 
 
 
static void
 
append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
 
             bfd_reloc_code_real_type *reloc_type, bfd_boolean expansionp)
 
{
 
  unsigned long prev_pinfo2, pinfo;
 
  bfd_boolean relaxed_branch = FALSE;
 
  enum append_method method;
 
  bfd_boolean relax32;
 
  int branch_disp;
 
 
 
  if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
 
    fix_loongson2f (ip);
 
 
 
  mips_mark_labels ();
 
 
 
  file_ase_mips16 |= mips_opts.mips16;
 
  file_ase_micromips |= mips_opts.micromips;
 
 
 
  prev_pinfo2 = history[0].insn_mo->pinfo2;
 
  pinfo = ip->insn_mo->pinfo;
 
 
 
  if (mips_opts.micromips
 
      && !expansionp
 
      && (((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0
 
           && micromips_insn_length (ip->insn_mo) != 2)
 
          || ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0
 
              && micromips_insn_length (ip->insn_mo) != 4)))
 
    as_warn (_("Wrong size instruction in a %u-bit branch delay slot"),
 
             (prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0 ? 16 : 32);
 
 
 
  if (address_expr == NULL)
 
    ip->complete_p = 1;
 
  else if (*reloc_type <= BFD_RELOC_UNUSED
 
           && address_expr->X_op == O_constant)
 
    {
 
      unsigned int tmp;
 
 
 
      ip->complete_p = 1;
 
      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:
 
          {
 
            int shift;
 
 
 
            shift = mips_opts.micromips ? 1 : 2;
 
            if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
 
              as_bad (_("jump to misaligned address (0x%lx)"),
 
                      (unsigned long) address_expr->X_add_number);
 
            ip->insn_opcode |= ((address_expr->X_add_number >> shift)
 
                                & 0x3ffffff);
 
            ip->complete_p = 0;
 
          }
 
          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));
 
          ip->complete_p = 0;
 
          break;
 
 
 
        case BFD_RELOC_16_PCREL_S2:
 
          {
 
            int shift;
 
 
 
            shift = mips_opts.micromips ? 1 : 2;
 
            if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0)
 
              as_bad (_("branch to misaligned address (0x%lx)"),
 
                      (unsigned long) address_expr->X_add_number);
 
            if (!mips_relax_branch)
 
              {
 
                if ((address_expr->X_add_number + (1 << (shift + 15)))
 
                    & ~((1 << (shift + 16)) - 1))
 
                  as_bad (_("branch address range overflow (0x%lx)"),
 
                          (unsigned long) address_expr->X_add_number);
 
                ip->insn_opcode |= ((address_expr->X_add_number >> shift)
 
                                    & 0xffff);
 
              }
 
            ip->complete_p = 0;
 
          }
 
          break;
 
 
 
        default:
 
          internalError ();
 
        }
 
    }
 
 
 
  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
         If you use gcc with optimization, it will reorder
         instructions and generally do much more optimization then we
         instructions and generally do much more optimization then we
         do here; repeating all that work in the assembler would only
         do here; repeating all that work in the assembler would only
         benefit hand written assembly code, and does not seem worth
         benefit hand written assembly code, and does not seem worth
         it.  */
         it.  */
      int nops = (mips_optimize == 0
      int nops = (mips_optimize == 0
                  ? nops_for_insn (history, NULL)
                  ? nops_for_insn (0, history, NULL)
                  : nops_for_insn_or_target (history, ip));
                  : nops_for_insn_or_target (0, history, ip));
      if (nops > 0)
      if (nops > 0)
        {
        {
          fragS *old_frag;
          fragS *old_frag;
          unsigned long old_frag_offset;
          unsigned long old_frag_offset;
          int i;
          int i;
 
 
          old_frag = frag_now;
          old_frag = frag_now;
          old_frag_offset = frag_now_fix ();
          old_frag_offset = frag_now_fix ();
 
 
          for (i = 0; i < nops; i++)
          for (i = 0; i < nops; i++)
            emit_nop ();
            add_fixed_insn (NOP_INSN);
 
          insert_into_history (0, nops, NOP_INSN);
 
 
          if (listing)
          if (listing)
            {
            {
              listing_prev_line ();
              listing_prev_line ();
              /* We may be at the start of a variant frag.  In case we
              /* We may be at the start of a variant frag.  In case we
Line 3152... Line 4149...
#endif
#endif
        }
        }
    }
    }
  else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
  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;
      int nops = nops_for_insn_or_target (history, ip);
 
 
      /* Work out how many nops in prev_nop_frag are needed by IP,
 
         ignoring hazards generated by the first prev_nop_frag_since
 
         instructions.  */
 
      nops = nops_for_insn_or_target (prev_nop_frag_since, history, ip);
      gas_assert (nops <= prev_nop_frag_holds);
      gas_assert (nops <= prev_nop_frag_holds);
 
 
      /* Enforce NOPS as a minimum.  */
      /* Enforce NOPS as a minimum.  */
      if (nops > prev_nop_frag_required)
      if (nops > prev_nop_frag_required)
        prev_nop_frag_required = nops;
        prev_nop_frag_required = nops;
Line 3172... Line 4173...
        }
        }
      else
      else
        {
        {
          /* Allow this instruction to replace one of the nops that was
          /* Allow this instruction to replace one of the nops that was
             tentatively added to prev_nop_frag.  */
             tentatively added to prev_nop_frag.  */
          prev_nop_frag->fr_fix -= mips_opts.mips16 ? 2 : 4;
          prev_nop_frag->fr_fix -= NOP_INSN_SIZE;
          prev_nop_frag_holds--;
          prev_nop_frag_holds--;
          prev_nop_frag_since++;
          prev_nop_frag_since++;
        }
        }
    }
    }
 
 
 
  method = get_append_method (ip);
 
  branch_disp = method == APPEND_SWAP ? insn_length (history) : 0;
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  /* The value passed to dwarf2_emit_insn is the distance between
  /* The value passed to dwarf2_emit_insn is the distance between
     the beginning of the current instruction and the address that
     the beginning of the current instruction and the address that
     should be recorded in the debug tables.  For MIPS16 debug info
     should be recorded in the debug tables.  This is normally the
     we want to use ISA-encoded addresses, so we pass -1 for an
     current address.
     address higher by one than the current.  */
 
  dwarf2_emit_insn (mips_opts.mips16 ? -1 : 0);
 
#endif
 
 
 
  /* Record the frag type before frag_var.  */
     For MIPS16/microMIPS debug info we want to use ISA-encoded
  if (history[0].frag)
     addresses, so we use -1 for an address higher by one than the
    prev_insn_frag_type = history[0].frag->fr_type;
     current one.
 
 
 
     If the instruction produced is a branch that we will swap with
 
     the preceding instruction, then we add the displacement by which
 
     the branch will be moved backwards.  This is more appropriate
 
     and for MIPS16/microMIPS code also prevents a debugger from
 
     placing a breakpoint in the middle of the branch (and corrupting
 
     code if software breakpoints are used).  */
 
  dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0) + branch_disp);
 
#endif
 
 
  if (address_expr
  relax32 = (mips_relax_branch
      && *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
      /* Don't try branch relaxation within .set nomacro, or within
         .set noat if we use $at for PIC computations.  If it turns
         .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.  */
         out that the branch was out-of-range, we'll get an error.  */
      && !mips_opts.warn_about_macros
      && !mips_opts.warn_about_macros
      && (mips_opts.at || mips_pic == NO_PIC)
      && (mips_opts.at || mips_pic == NO_PIC)
      /* Don't relax BPOSGE32/64 as they have no complementing branches.  */
             /* Don't relax BPOSGE32/64 as they have no complementing
      && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP))
                branches.  */
      && !mips_opts.mips16)
             && !(ip->insn_mo->membership & (INSN_DSP64 | INSN_DSP)));
 
 
 
  if (!HAVE_CODE_COMPRESSION
 
      && address_expr
 
      && relax32
 
      && *reloc_type == BFD_RELOC_16_PCREL_S2
 
      && delayed_branch_p (ip))
    {
    {
      relaxed_branch = TRUE;
      relaxed_branch = TRUE;
      add_relaxed_insn (ip, (relaxed_branch_length
      add_relaxed_insn (ip, (relaxed_branch_length
                             (NULL, NULL,
                             (NULL, NULL,
                              (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
                              uncond_branch_p (ip) ? -1
                              : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
                              : branch_likely_p (ip) ? 1
                              : 0)), 4,
                              : 0)), 4,
                        RELAX_BRANCH_ENCODE
                        RELAX_BRANCH_ENCODE
                        (AT,
                        (AT,
                         pinfo & INSN_UNCOND_BRANCH_DELAY,
                         uncond_branch_p (ip),
                         pinfo & INSN_COND_BRANCH_LIKELY,
                         branch_likely_p (ip),
                         pinfo & INSN_WRITE_GPR_31,
                         pinfo & INSN_WRITE_GPR_31,
                         0),
                         0),
                        address_expr->X_add_symbol,
                        address_expr->X_add_symbol,
                        address_expr->X_add_number);
                        address_expr->X_add_number);
      *reloc_type = BFD_RELOC_UNUSED;
      *reloc_type = BFD_RELOC_UNUSED;
    }
    }
  else if (*reloc_type > BFD_RELOC_UNUSED)
  else if (mips_opts.micromips
 
           && address_expr
 
           && ((relax32 && *reloc_type == BFD_RELOC_16_PCREL_S2)
 
               || *reloc_type > BFD_RELOC_UNUSED)
 
           && (delayed_branch_p (ip) || compact_branch_p (ip))
 
           /* Don't try branch relaxation when users specify
 
              16-bit/32-bit instructions.  */
 
           && !forced_insn_length)
 
    {
 
      bfd_boolean relax16 = *reloc_type > BFD_RELOC_UNUSED;
 
      int type = relax16 ? *reloc_type - BFD_RELOC_UNUSED : 0;
 
      int uncond = uncond_branch_p (ip) ? -1 : 0;
 
      int compact = compact_branch_p (ip);
 
      int al = pinfo & INSN_WRITE_GPR_31;
 
      int length32;
 
 
 
      gas_assert (address_expr != NULL);
 
      gas_assert (!mips_relax.sequence);
 
 
 
      relaxed_branch = TRUE;
 
      length32 = relaxed_micromips_32bit_branch_length (NULL, NULL, uncond);
 
      add_relaxed_insn (ip, relax32 ? length32 : 4, relax16 ? 2 : 4,
 
                        RELAX_MICROMIPS_ENCODE (type, AT, uncond, compact, al,
 
                                                relax32, 0, 0),
 
                        address_expr->X_add_symbol,
 
                        address_expr->X_add_number);
 
      *reloc_type = BFD_RELOC_UNUSED;
 
    }
 
  else if (mips_opts.mips16 && *reloc_type > BFD_RELOC_UNUSED)
    {
    {
      /* We need to set up a variant frag.  */
      /* We need to set up a variant frag.  */
      gas_assert (mips_opts.mips16 && address_expr != NULL);
      gas_assert (address_expr != NULL);
      add_relaxed_insn (ip, 4, 0,
      add_relaxed_insn (ip, 4, 0,
                        RELAX_MIPS16_ENCODE
                        RELAX_MIPS16_ENCODE
                        (*reloc_type - BFD_RELOC_UNUSED,
                        (*reloc_type - BFD_RELOC_UNUSED,
                         mips16_small, mips16_ext,
                         forced_insn_length == 2, forced_insn_length == 4,
                         prev_pinfo & INSN_UNCOND_BRANCH_DELAY,
                         delayed_branch_p (&history[0]),
                         history[0].mips16_absolute_jump_p),
                         history[0].mips16_absolute_jump_p),
                        make_expr_symbol (address_expr), 0);
                        make_expr_symbol (address_expr), 0);
    }
    }
  else if (mips_opts.mips16
  else if (mips_opts.mips16
           && ! ip->use_extend
           && ! ip->use_extend
           && *reloc_type != BFD_RELOC_MIPS16_JMP)
           && *reloc_type != BFD_RELOC_MIPS16_JMP)
    {
    {
      if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
      if (!delayed_branch_p (ip))
        /* Make sure there is enough room to swap this instruction with
        /* Make sure there is enough room to swap this instruction with
           a following jump instruction.  */
           a following jump instruction.  */
        frag_grow (6);
        frag_grow (6);
      add_fixed_insn (ip);
      add_fixed_insn (ip);
    }
    }
  else
  else
    {
    {
      if (mips_opts.mips16
      if (mips_opts.mips16
          && mips_opts.noreorder
          && mips_opts.noreorder
          && (prev_pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
          && delayed_branch_p (&history[0]))
        as_warn (_("extended instruction in delay slot"));
        as_warn (_("extended instruction in delay slot"));
 
 
      if (mips_relax.sequence)
      if (mips_relax.sequence)
        {
        {
          /* If we've reached the end of this frag, turn it into a variant
          /* If we've reached the end of this frag, turn it into a variant
             frag and record the information for the instructions we've
             frag and record the information for the instructions we've
             written so far.  */
             written so far.  */
          if (frag_room () < 4)
          if (frag_room () < 4)
            relax_close_frag ();
            relax_close_frag ();
          mips_relax.sizes[mips_relax.sequence - 1] += 4;
          mips_relax.sizes[mips_relax.sequence - 1] += insn_length (ip);
        }
        }
 
 
      if (mips_relax.sequence != 2)
      if (mips_relax.sequence != 2)
        mips_macro_warning.sizes[0] += 4;
        {
 
          if (mips_macro_warning.first_insn_sizes[0] == 0)
 
            mips_macro_warning.first_insn_sizes[0] = insn_length (ip);
 
          mips_macro_warning.sizes[0] += insn_length (ip);
 
          mips_macro_warning.insns[0]++;
 
        }
      if (mips_relax.sequence != 1)
      if (mips_relax.sequence != 1)
        mips_macro_warning.sizes[1] += 4;
        {
 
          if (mips_macro_warning.first_insn_sizes[1] == 0)
 
            mips_macro_warning.first_insn_sizes[1] = insn_length (ip);
 
          mips_macro_warning.sizes[1] += insn_length (ip);
 
          mips_macro_warning.insns[1]++;
 
        }
 
 
      if (mips_opts.mips16)
      if (mips_opts.mips16)
        {
        {
          ip->fixed_p = 1;
          ip->fixed_p = 1;
          ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP);
          ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP);
        }
        }
      add_fixed_insn (ip);
      add_fixed_insn (ip);
    }
    }
 
 
  if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
  if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
    {
 
      if (!ip->complete_p
 
          && *reloc_type < BFD_RELOC_UNUSED)
 
        need_reloc:
 
        {
        {
 
      bfd_reloc_code_real_type final_type[3];
 
      reloc_howto_type *howto0;
          reloc_howto_type *howto;
          reloc_howto_type *howto;
          int i;
          int i;
 
 
 
      /* Perform any necessary conversion to microMIPS relocations
 
         and find out how many relocations there actually are.  */
 
      for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++)
 
        final_type[i] = micromips_map_reloc (reloc_type[i]);
 
 
          /* In a compound relocation, it is the final (outermost)
          /* In a compound relocation, it is the final (outermost)
             operator that determines the relocated field.  */
             operator that determines the relocated field.  */
          for (i = 1; i < 3; i++)
      howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
            if (reloc_type[i] == BFD_RELOC_UNUSED)
 
              break;
 
 
 
          howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
 
          if (howto == NULL)
          if (howto == NULL)
            {
            {
              /* To reproduce this failure try assembling gas/testsuites/
              /* To reproduce this failure try assembling gas/testsuites/
                 gas/mips/mips16-intermix.s with a mips-ecoff targeted
                 gas/mips/mips16-intermix.s with a mips-ecoff targeted
                 assembler.  */
                 assembler.  */
              as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]);
          as_bad (_("Unsupported MIPS relocation number %d"),
 
                  final_type[i - 1]);
              howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
              howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
            }
            }
 
 
 
      if (i > 1)
 
        howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
          ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
          ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
                                     bfd_get_reloc_size (howto),
                                     bfd_get_reloc_size (howto),
                                     address_expr,
                                     address_expr,
                                     reloc_type[0] == BFD_RELOC_16_PCREL_S2,
                                 howto0 && howto0->pc_relative,
                                     reloc_type[0]);
                                 final_type[0]);
 
 
          /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
          /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
          if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
      if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy)
              && ip->fixp[0]->fx_addsy)
 
            *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
            *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
 
 
          /* These relocations can have an addend that won't fit in
          /* These relocations can have an addend that won't fit in
             4 octets for 64bit assembly.  */
             4 octets for 64bit assembly.  */
          if (HAVE_64BIT_GPRS
          if (HAVE_64BIT_GPRS
Line 3365... Line 4417...
          for (i = 1; i < 3; i++)
          for (i = 1; i < 3; i++)
            if (reloc_type[i] != BFD_RELOC_UNUSED)
            if (reloc_type[i] != BFD_RELOC_UNUSED)
              {
              {
                ip->fixp[i] = fix_new (ip->frag, ip->where,
                ip->fixp[i] = fix_new (ip->frag, ip->where,
                                       ip->fixp[0]->fx_size, NULL, 0,
                                       ip->fixp[0]->fx_size, NULL, 0,
                                       FALSE, reloc_type[i]);
                                   FALSE, final_type[i]);
 
 
                /* Use fx_tcbit to mark compound relocs.  */
                /* Use fx_tcbit to mark compound relocs.  */
                ip->fixp[0]->fx_tcbit = 1;
                ip->fixp[0]->fx_tcbit = 1;
                ip->fixp[i]->fx_tcbit = 1;
                ip->fixp[i]->fx_tcbit = 1;
              }
              }
        }
        }
    }
 
  install_insn (ip);
  install_insn (ip);
 
 
  /* Update the register mask information.  */
  /* Update the register mask information.  */
  if (! mips_opts.mips16)
  mips_gprmask |= gpr_read_mask (ip) | gpr_write_mask (ip);
 
  mips_cprmask[1] |= fpr_read_mask (ip) | fpr_write_mask (ip);
 
 
 
  switch (method)
    {
    {
      if ((pinfo & INSN_WRITE_GPR_D) || (pinfo2 & INSN2_READ_GPR_D))
    case APPEND_ADD:
        mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
      insert_into_history (0, 1, ip);
      if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
      break;
        mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
 
      if (pinfo & INSN_READ_GPR_S)
    case APPEND_ADD_WITH_NOP:
        mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
 
      if (pinfo & INSN_WRITE_GPR_31)
 
        mips_gprmask |= 1 << RA;
 
      if (pinfo2 & (INSN2_WRITE_GPR_Z | INSN2_READ_GPR_Z))
 
        mips_gprmask |= 1 << EXTRACT_OPERAND (RZ, *ip);
 
      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 (pinfo2 & (INSN2_WRITE_FPR_Z | INSN2_READ_FPR_Z))
 
        mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FZ, *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))
        struct mips_cl_insn *nop;
        mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
 
      if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
        insert_into_history (0, 1, ip);
        mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
        nop = get_delay_slot_nop (ip);
      if (pinfo & MIPS16_INSN_WRITE_Z)
        add_fixed_insn (nop);
        mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
        insert_into_history (0, 1, nop);
      if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
        if (mips_relax.sequence)
        mips_gprmask |= 1 << TREG;
          mips_relax.sizes[mips_relax.sequence - 1] += insn_length (nop);
      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);
 
    }
    }
 
      break;
 
 
  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
    case APPEND_ADD_COMPACT:
    {
 
      /* 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_pinfo2 & INSN2_WRITE_GPR_Z)
 
                  && insn_uses_reg (ip, EXTRACT_OPERAND (RZ, 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 the previous instruction is an ERET or
 
                 DERET, avoid the swap.  */
 
              || (history[0].insn_opcode == INSN_ERET)
 
              || (history[0].insn_opcode == INSN_DERET))
 
            {
 
              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.  */
                  /* Convert MIPS16 jr/jalr into a "compact" jump.  */
 
      gas_assert (mips_opts.mips16);
                  ip->insn_opcode |= 0x0080;
                  ip->insn_opcode |= 0x0080;
 
      find_altered_mips16_opcode (ip);
                  install_insn (ip);
                  install_insn (ip);
                  insert_into_history (0, 1, ip);
                  insert_into_history (0, 1, ip);
                }
      break;
              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)
    case APPEND_SWAP:
                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];
              struct mips_cl_insn delay = history[0];
              if (mips_opts.mips16)
              if (mips_opts.mips16)
                {
                {
                  know (delay.frag == ip->frag);
                  know (delay.frag == ip->frag);
                  move_insn (ip, delay.frag, delay.where);
                  move_insn (ip, delay.frag, delay.where);
Line 3616... Line 4473...
                {
                {
                  /* Add the delay slot instruction to the end of the
                  /* Add the delay slot instruction to the end of the
                     current frag and shrink the fixed part of the
                     current frag and shrink the fixed part of the
                     original frag.  If the branch occupies the tail of
                     original frag.  If the branch occupies the tail of
                     the latter, move it backwards to cover the gap.  */
                     the latter, move it backwards to cover the gap.  */
                  delay.frag->fr_fix -= 4;
            delay.frag->fr_fix -= branch_disp;
                  if (delay.frag == ip->frag)
                  if (delay.frag == ip->frag)
                    move_insn (ip, ip->frag, ip->where - 4);
              move_insn (ip, ip->frag, ip->where - branch_disp);
                  add_fixed_insn (&delay);
                  add_fixed_insn (&delay);
                }
                }
              else
              else
                {
                {
                  move_insn (&delay, ip->frag, ip->where);
            move_insn (&delay, ip->frag,
 
                       ip->where - branch_disp + insn_length (ip));
                  move_insn (ip, history[0].frag, history[0].where);
                  move_insn (ip, history[0].frag, history[0].where);
                }
                }
              history[0] = *ip;
              history[0] = *ip;
              delay.fixed_p = 1;
              delay.fixed_p = 1;
              insert_into_history (0, 1, &delay);
              insert_into_history (0, 1, &delay);
            }
            }
 
      break;
 
    }
 
 
          /* If that was an unconditional branch, forget the previous
  /* If we have just completed an unconditional branch, clear the history.  */
             insn information.  */
  if ((delayed_branch_p (&history[1]) && uncond_branch_p (&history[1]))
          if (pinfo & INSN_UNCOND_BRANCH_DELAY)
      || (compact_branch_p (&history[0]) && uncond_branch_p (&history[0])))
            {
 
              mips_no_prev_insn ();
              mips_no_prev_insn ();
            }
 
        }
  /* We need to emit a label at the end of branch-likely macros.  */
      else if (pinfo & INSN_COND_BRANCH_LIKELY)
  if (emit_branch_likely_macro)
        {
        {
          /* We don't yet optimize a branch likely.  What we should do
      emit_branch_likely_macro = FALSE;
             is look at the target, copy the instruction found there
      micromips_add_label ();
             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.  */
  /* We just output an insn, so the next one doesn't have a label.  */
  mips_clear_insn_labels ();
  mips_clear_insn_labels ();
}
}
 
 
Line 3676... Line 4526...
void
void
mips_emit_delays (void)
mips_emit_delays (void)
{
{
  if (! mips_opts.noreorder)
  if (! mips_opts.noreorder)
    {
    {
      int nops = nops_for_insn (history, NULL);
      int nops = nops_for_insn (0, history, NULL);
      if (nops > 0)
      if (nops > 0)
        {
        {
          while (nops-- > 0)
          while (nops-- > 0)
            add_fixed_insn (NOP_INSN);
            add_fixed_insn (NOP_INSN);
          mips_move_labels ();
          mips_move_labels ();
Line 3704... Line 4554...
        history[i].fixed_p = 1;
        history[i].fixed_p = 1;
 
 
      /* Insert any nops that might be needed between the .set noreorder
      /* Insert any nops that might be needed between the .set noreorder
         block and the previous instructions.  We will later remove any
         block and the previous instructions.  We will later remove any
         nops that turn out not to be needed.  */
         nops that turn out not to be needed.  */
      nops = nops_for_insn (history, NULL);
      nops = nops_for_insn (0, history, NULL);
      if (nops > 0)
      if (nops > 0)
        {
        {
          if (mips_optimize != 0)
          if (mips_optimize != 0)
            {
            {
              /* Record the frag which holds the nop instructions, so
              /* Record the frag which holds the nop instructions, so
                 that we can remove them if we don't need them.  */
                 that we can remove them if we don't need them.  */
              frag_grow (mips_opts.mips16 ? nops * 2 : nops * 4);
              frag_grow (nops * NOP_INSN_SIZE);
              prev_nop_frag = frag_now;
              prev_nop_frag = frag_now;
              prev_nop_frag_holds = nops;
              prev_nop_frag_holds = nops;
              prev_nop_frag_required = 0;
              prev_nop_frag_required = 0;
              prev_nop_frag_since = 0;
              prev_nop_frag_since = 0;
            }
            }
Line 3727... Line 4577...
             decrease the size of prev_nop_frag.  */
             decrease the size of prev_nop_frag.  */
          frag_wane (frag_now);
          frag_wane (frag_now);
          frag_new (0);
          frag_new (0);
          mips_move_labels ();
          mips_move_labels ();
        }
        }
      mips16_mark_labels ();
      mips_mark_labels ();
      mips_clear_insn_labels ();
      mips_clear_insn_labels ();
    }
    }
  mips_opts.noreorder++;
  mips_opts.noreorder++;
  mips_any_noreorder = 1;
  mips_any_noreorder = 1;
}
}
Line 3746... Line 4596...
  if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
  if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
    {
    {
      /* Commit to inserting prev_nop_frag_required nops and go back to
      /* Commit to inserting prev_nop_frag_required nops and go back to
         handling nop insertion the .set reorder way.  */
         handling nop insertion the .set reorder way.  */
      prev_nop_frag->fr_fix -= ((prev_nop_frag_holds - prev_nop_frag_required)
      prev_nop_frag->fr_fix -= ((prev_nop_frag_holds - prev_nop_frag_required)
                                * (mips_opts.mips16 ? 2 : 4));
                                * NOP_INSN_SIZE);
      insert_into_history (prev_nop_frag_since,
      insert_into_history (prev_nop_frag_since,
                           prev_nop_frag_required, NOP_INSN);
                           prev_nop_frag_required, NOP_INSN);
      prev_nop_frag = NULL;
      prev_nop_frag = NULL;
    }
    }
}
}
Line 3759... Line 4609...
 
 
static void
static void
macro_start (void)
macro_start (void)
{
{
  memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
  memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
 
  memset (&mips_macro_warning.first_insn_sizes, 0,
 
          sizeof (mips_macro_warning.first_insn_sizes));
 
  memset (&mips_macro_warning.insns, 0, sizeof (mips_macro_warning.insns));
  mips_macro_warning.delay_slot_p = (mips_opts.noreorder
  mips_macro_warning.delay_slot_p = (mips_opts.noreorder
                                     && (history[0].insn_mo->pinfo
                                     && delayed_branch_p (&history[0]));
                                         & (INSN_UNCOND_BRANCH_DELAY
  switch (history[0].insn_mo->pinfo2
                                            | INSN_COND_BRANCH_DELAY
          & (INSN2_BRANCH_DELAY_32BIT | INSN2_BRANCH_DELAY_16BIT))
                                            | INSN_COND_BRANCH_LIKELY)) != 0);
    {
}
    case INSN2_BRANCH_DELAY_32BIT:
 
      mips_macro_warning.delay_slot_length = 4;
/* Given that a macro is longer than 4 bytes, return the appropriate warning
      break;
   for it.  Return null if no warning is needed.  SUBTYPE is a bitmask of
    case INSN2_BRANCH_DELAY_16BIT:
   RELAX_DELAY_SLOT and RELAX_NOMACRO.  */
      mips_macro_warning.delay_slot_length = 2;
 
      break;
static const char *
    default:
macro_warning (relax_substateT subtype)
      mips_macro_warning.delay_slot_length = 0;
 
      break;
 
    }
 
  mips_macro_warning.first_frag = NULL;
 
}
 
 
 
/* Given that a macro is longer than one instruction or of the wrong size,
 
   return the appropriate warning for it.  Return null if no warning is
 
   needed.  SUBTYPE is a bitmask of RELAX_DELAY_SLOT, RELAX_DELAY_SLOT_16BIT,
 
   RELAX_DELAY_SLOT_SIZE_FIRST, RELAX_DELAY_SLOT_SIZE_SECOND,
 
   and RELAX_NOMACRO.  */
 
 
 
static const char *
 
macro_warning (relax_substateT subtype)
{
{
  if (subtype & RELAX_DELAY_SLOT)
  if (subtype & RELAX_DELAY_SLOT)
    return _("Macro instruction expanded into multiple instructions"
    return _("Macro instruction expanded into multiple instructions"
             " in a branch delay slot");
             " in a branch delay slot");
  else if (subtype & RELAX_NOMACRO)
  else if (subtype & RELAX_NOMACRO)
    return _("Macro instruction expanded into multiple instructions");
    return _("Macro instruction expanded into multiple instructions");
 
  else if (subtype & (RELAX_DELAY_SLOT_SIZE_FIRST
 
                      | RELAX_DELAY_SLOT_SIZE_SECOND))
 
    return ((subtype & RELAX_DELAY_SLOT_16BIT)
 
            ? _("Macro instruction expanded into a wrong size instruction"
 
                " in a 16-bit branch delay slot")
 
            : _("Macro instruction expanded into a wrong size instruction"
 
                " in a 32-bit branch delay slot"));
  else
  else
    return 0;
    return 0;
}
}
 
 
/* Finish up a macro.  Emit warnings as appropriate.  */
/* Finish up a macro.  Emit warnings as appropriate.  */
 
 
static void
static void
macro_end (void)
macro_end (void)
{
{
  if (mips_macro_warning.sizes[0] > 4 || mips_macro_warning.sizes[1] > 4)
  /* Relaxation warning flags.  */
    {
  relax_substateT subtype = 0;
      relax_substateT subtype;
 
 
 
      /* Set up the relaxation warning flags.  */
  /* Check delay slot size requirements.  */
      subtype = 0;
  if (mips_macro_warning.delay_slot_length == 2)
      if (mips_macro_warning.sizes[1] > mips_macro_warning.sizes[0])
    subtype |= RELAX_DELAY_SLOT_16BIT;
 
  if (mips_macro_warning.delay_slot_length != 0)
 
    {
 
      if (mips_macro_warning.delay_slot_length
 
          != mips_macro_warning.first_insn_sizes[0])
 
        subtype |= RELAX_DELAY_SLOT_SIZE_FIRST;
 
      if (mips_macro_warning.delay_slot_length
 
          != mips_macro_warning.first_insn_sizes[1])
 
        subtype |= RELAX_DELAY_SLOT_SIZE_SECOND;
 
    }
 
 
 
  /* Check instruction count requirements.  */
 
  if (mips_macro_warning.insns[0] > 1 || mips_macro_warning.insns[1] > 1)
 
    {
 
      if (mips_macro_warning.insns[1] > mips_macro_warning.insns[0])
        subtype |= RELAX_SECOND_LONGER;
        subtype |= RELAX_SECOND_LONGER;
      if (mips_opts.warn_about_macros)
      if (mips_opts.warn_about_macros)
        subtype |= RELAX_NOMACRO;
        subtype |= RELAX_NOMACRO;
      if (mips_macro_warning.delay_slot_p)
      if (mips_macro_warning.delay_slot_p)
        subtype |= RELAX_DELAY_SLOT;
        subtype |= RELAX_DELAY_SLOT;
 
    }
 
 
      if (mips_macro_warning.sizes[0] > 4 && mips_macro_warning.sizes[1] > 4)
  /* If both alternatives fail to fill a delay slot correctly,
        {
     emit the warning now.  */
          /* Either the macro has a single implementation or both
  if ((subtype & RELAX_DELAY_SLOT_SIZE_FIRST) != 0
             implementations are longer than 4 bytes.  Emit the
      && (subtype & RELAX_DELAY_SLOT_SIZE_SECOND) != 0)
             warning now.  */
    {
          const char *msg = macro_warning (subtype);
      relax_substateT s;
          if (msg != 0)
      const char *msg;
 
 
 
      s = subtype & (RELAX_DELAY_SLOT_16BIT
 
                     | RELAX_DELAY_SLOT_SIZE_FIRST
 
                     | RELAX_DELAY_SLOT_SIZE_SECOND);
 
      msg = macro_warning (s);
 
      if (msg != NULL)
            as_warn ("%s", msg);
            as_warn ("%s", msg);
 
      subtype &= ~s;
        }
        }
      else
 
 
  /* If both implementations are longer than 1 instruction, then emit the
 
     warning now.  */
 
  if (mips_macro_warning.insns[0] > 1 && mips_macro_warning.insns[1] > 1)
        {
        {
          /* One implementation might need a warning but the other
      relax_substateT s;
             definitely doesn't.  */
      const char *msg;
          mips_macro_warning.first_frag->fr_subtype |= subtype;
 
        }
      s = subtype & (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT);
 
      msg = macro_warning (s);
 
      if (msg != NULL)
 
        as_warn ("%s", msg);
 
      subtype &= ~s;
    }
    }
 
 
 
  /* If any flags still set, then one implementation might need a warning
 
     and the other either will need one of a different kind or none at all.
 
     Pass any remaining flags over to relaxation.  */
 
  if (mips_macro_warning.first_frag != NULL)
 
    mips_macro_warning.first_frag->fr_subtype |= subtype;
}
}
 
 
 
/* Instruction operand formats used in macros that vary between
 
   standard MIPS and microMIPS code.  */
 
 
 
static const char * const brk_fmt[2] = { "c", "mF" };
 
static const char * const cop12_fmt[2] = { "E,o(b)", "E,~(b)" };
 
static const char * const jalr_fmt[2] = { "d,s", "t,s" };
 
static const char * const lui_fmt[2] = { "t,u", "s,u" };
 
static const char * const mem12_fmt[2] = { "t,o(b)", "t,~(b)" };
 
static const char * const mfhl_fmt[2] = { "d", "mj" };
 
static const char * const shft_fmt[2] = { "d,w,<", "t,r,<" };
 
static const char * const trap_fmt[2] = { "s,t,q", "s,t,|" };
 
 
 
#define BRK_FMT (brk_fmt[mips_opts.micromips])
 
#define COP12_FMT (cop12_fmt[mips_opts.micromips])
 
#define JALR_FMT (jalr_fmt[mips_opts.micromips])
 
#define LUI_FMT (lui_fmt[mips_opts.micromips])
 
#define MEM12_FMT (mem12_fmt[mips_opts.micromips])
 
#define MFHL_FMT (mfhl_fmt[mips_opts.micromips])
 
#define SHFT_FMT (shft_fmt[mips_opts.micromips])
 
#define TRAP_FMT (trap_fmt[mips_opts.micromips])
 
 
/* Read a macro's relocation codes from *ARGS and store them in *R.
/* Read a macro's relocation codes from *ARGS and store them in *R.
   The first argument in *ARGS will be either the code for a single
   The first argument in *ARGS will be either the code for a single
   relocation or -1 followed by the three codes that make up a
   relocation or -1 followed by the three codes that make up a
   composite relocation.  */
   composite relocation.  */
 
 
Line 3844... Line 4772...
   string, and corresponding arguments.  */
   string, and corresponding arguments.  */
 
 
static void
static void
macro_build (expressionS *ep, const char *name, const char *fmt, ...)
macro_build (expressionS *ep, const char *name, const char *fmt, ...)
{
{
  const struct mips_opcode *mo;
  const struct mips_opcode *mo = NULL;
  struct mips_cl_insn insn;
 
  bfd_reloc_code_real_type r[3];
  bfd_reloc_code_real_type r[3];
 
  const struct mips_opcode *amo;
 
  struct hash_control *hash;
 
  struct mips_cl_insn insn;
  va_list args;
  va_list args;
 
 
  va_start (args, fmt);
  va_start (args, fmt);
 
 
  if (mips_opts.mips16)
  if (mips_opts.mips16)
Line 3861... Line 4791...
    }
    }
 
 
  r[0] = BFD_RELOC_UNUSED;
  r[0] = BFD_RELOC_UNUSED;
  r[1] = BFD_RELOC_UNUSED;
  r[1] = BFD_RELOC_UNUSED;
  r[2] = BFD_RELOC_UNUSED;
  r[2] = BFD_RELOC_UNUSED;
  mo = (struct mips_opcode *) hash_find (op_hash, name);
  hash = mips_opts.micromips ? micromips_op_hash : op_hash;
  gas_assert (mo);
  amo = (struct mips_opcode *) hash_find (hash, name);
  gas_assert (strcmp (name, mo->name) == 0);
  gas_assert (amo);
 
  gas_assert (strcmp (name, amo->name) == 0);
 
 
  while (1)
  do
    {
    {
      /* Search until we get a match for NAME.  It is assumed here that
      /* Search until we get a match for NAME.  It is assumed here that
         macros will never generate MDMX, MIPS-3D, or MT instructions.  */
         macros will never generate MDMX, MIPS-3D, or MT instructions.
      if (strcmp (fmt, mo->args) == 0
         We try to match an instruction that fulfils the branch delay
          && mo->pinfo != INSN_MACRO
         slot instruction length requirement (if any) of the previous
          && is_opcode_valid (mo))
         instruction.  While doing this we record the first instruction
 
         seen that matches all the other conditions and use it anyway
 
         if the requirement cannot be met; we will issue an appropriate
 
         warning later on.  */
 
      if (strcmp (fmt, amo->args) == 0
 
          && amo->pinfo != INSN_MACRO
 
          && is_opcode_valid (amo)
 
          && is_size_valid (amo))
 
        {
 
          if (is_delay_slot_valid (amo))
 
            {
 
              mo = amo;
        break;
        break;
 
            }
 
          else if (!mo)
 
            mo = amo;
 
        }
 
 
      ++mo;
      ++amo;
      gas_assert (mo->name);
      gas_assert (amo->name);
      gas_assert (strcmp (name, mo->name) == 0);
 
    }
    }
 
  while (strcmp (name, amo->name) == 0);
 
 
 
  gas_assert (mo);
  create_insn (&insn, mo);
  create_insn (&insn, mo);
  for (;;)
  for (;;)
    {
    {
      switch (*fmt++)
      switch (*fmt++)
        {
        {
Line 3897... Line 4844...
        case '+':
        case '+':
          switch (*fmt++)
          switch (*fmt++)
            {
            {
            case 'A':
            case 'A':
            case 'E':
            case 'E':
              INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
              INSERT_OPERAND (mips_opts.micromips,
 
                              EXTLSB, insn, va_arg (args, int));
              continue;
              continue;
 
 
            case 'B':
            case 'B':
            case 'F':
            case 'F':
              /* Note that in the macro case, these arguments are already
              /* Note that in the macro case, these arguments are already
                 in MSB form.  (When handling the instruction in the
                 in MSB form.  (When handling the instruction in the
                 non-macro case, these arguments are sizes from which
                 non-macro case, these arguments are sizes from which
                 MSB values must be calculated.)  */
                 MSB values must be calculated.)  */
              INSERT_OPERAND (INSMSB, insn, va_arg (args, int));
              INSERT_OPERAND (mips_opts.micromips,
 
                              INSMSB, insn, va_arg (args, int));
              continue;
              continue;
 
 
            case 'C':
            case 'C':
            case 'G':
            case 'G':
            case 'H':
            case 'H':
              /* Note that in the macro case, these arguments are already
              /* Note that in the macro case, these arguments are already
                 in MSBD form.  (When handling the instruction in the
                 in MSBD form.  (When handling the instruction in the
                 non-macro case, these arguments are sizes from which
                 non-macro case, these arguments are sizes from which
                 MSBD values must be calculated.)  */
                 MSBD values must be calculated.)  */
              INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
              INSERT_OPERAND (mips_opts.micromips,
 
                              EXTMSBD, insn, va_arg (args, int));
              continue;
              continue;
 
 
            case 'Q':
            case 'Q':
              INSERT_OPERAND (SEQI, insn, va_arg (args, int));
              gas_assert (!mips_opts.micromips);
 
              INSERT_OPERAND (0, SEQI, insn, va_arg (args, int));
              continue;
              continue;
 
 
            default:
            default:
              internalError ();
              internalError ();
            }
            }
          continue;
          continue;
 
 
        case '2':
        case '2':
          INSERT_OPERAND (BP, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, BP, insn, va_arg (args, int));
          continue;
          continue;
 
 
 
        case 'n':
 
          gas_assert (mips_opts.micromips);
        case 't':
        case 't':
        case 'w':
        case 'w':
        case 'E':
        case 'E':
          INSERT_OPERAND (RT, insn, va_arg (args, int));
          INSERT_OPERAND (mips_opts.micromips, RT, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'c':
        case 'c':
          INSERT_OPERAND (CODE, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, CODE, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'T':
 
        case 'W':
        case 'W':
          INSERT_OPERAND (FT, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
        case 'T':
 
          INSERT_OPERAND (mips_opts.micromips, FT, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'd':
 
        case 'G':
        case 'G':
 
          if (mips_opts.micromips)
 
            INSERT_OPERAND (1, RS, insn, va_arg (args, int));
 
          else
 
            INSERT_OPERAND (0, RD, insn, va_arg (args, int));
 
          continue;
 
 
        case 'K':
        case 'K':
          INSERT_OPERAND (RD, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
        case 'd':
 
          INSERT_OPERAND (mips_opts.micromips, RD, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'U':
        case 'U':
 
          gas_assert (!mips_opts.micromips);
          {
          {
            int tmp = va_arg (args, int);
            int tmp = va_arg (args, int);
 
 
            INSERT_OPERAND (RT, insn, tmp);
            INSERT_OPERAND (0, RT, insn, tmp);
            INSERT_OPERAND (RD, insn, tmp);
            INSERT_OPERAND (0, RD, insn, tmp);
            continue;
 
          }
          }
 
          continue;
 
 
        case 'V':
        case 'V':
        case 'S':
        case 'S':
          INSERT_OPERAND (FS, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, FS, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'z':
        case 'z':
          continue;
          continue;
 
 
        case '<':
        case '<':
          INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
          INSERT_OPERAND (mips_opts.micromips,
 
                          SHAMT, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'D':
        case 'D':
          INSERT_OPERAND (FD, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, FD, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'B':
        case 'B':
          INSERT_OPERAND (CODE20, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, CODE20, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'J':
        case 'J':
          INSERT_OPERAND (CODE19, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, CODE19, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'q':
        case 'q':
          INSERT_OPERAND (CODE2, insn, va_arg (args, int));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, CODE2, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'b':
        case 'b':
        case 's':
        case 's':
        case 'r':
        case 'r':
        case 'v':
        case 'v':
          INSERT_OPERAND (RS, insn, va_arg (args, int));
          INSERT_OPERAND (mips_opts.micromips, RS, insn, va_arg (args, int));
          continue;
          continue;
 
 
        case 'i':
        case 'i':
        case 'j':
        case 'j':
          macro_read_relocs (&args, r);
          macro_read_relocs (&args, r);
Line 4036... Line 5006...
           * We don't allow branch relaxation for these branches, as
           * We don't allow branch relaxation for these branches, as
           * they should only appear in ".set nomacro" anyway.
           * they should only appear in ".set nomacro" anyway.
           */
           */
          if (ep->X_op == O_constant)
          if (ep->X_op == O_constant)
            {
            {
 
              /* For microMIPS we always use relocations for branches.
 
                 So we should not resolve immediate values.  */
 
              gas_assert (!mips_opts.micromips);
 
 
              if ((ep->X_add_number & 3) != 0)
              if ((ep->X_add_number & 3) != 0)
                as_bad (_("branch to misaligned address (0x%lx)"),
                as_bad (_("branch to misaligned address (0x%lx)"),
                        (unsigned long) ep->X_add_number);
                        (unsigned long) ep->X_add_number);
              if ((ep->X_add_number + 0x20000) & ~0x3ffff)
              if ((ep->X_add_number + 0x20000) & ~0x3ffff)
                as_bad (_("branch address range overflow (0x%lx)"),
                as_bad (_("branch address range overflow (0x%lx)"),
Line 4055... Line 5029...
          gas_assert (ep != NULL);
          gas_assert (ep != NULL);
          *r = BFD_RELOC_MIPS_JMP;
          *r = BFD_RELOC_MIPS_JMP;
          continue;
          continue;
 
 
        case 'C':
        case 'C':
          INSERT_OPERAND (COPZ, insn, va_arg (args, unsigned long));
          gas_assert (!mips_opts.micromips);
 
          INSERT_OPERAND (0, COPZ, insn, va_arg (args, unsigned long));
          continue;
          continue;
 
 
        case 'k':
        case 'k':
          INSERT_OPERAND (CACHE, insn, va_arg (args, unsigned long));
          INSERT_OPERAND (mips_opts.micromips,
 
                          CACHE, insn, va_arg (args, unsigned long));
 
          continue;
 
 
 
        case '|':
 
          gas_assert (mips_opts.micromips);
 
          INSERT_OPERAND (1, TRAP, insn, va_arg (args, int));
 
          continue;
 
 
 
        case '.':
 
          gas_assert (mips_opts.micromips);
 
          INSERT_OPERAND (1, OFFSET10, insn, va_arg (args, int));
 
          continue;
 
 
 
        case '\\':
 
          INSERT_OPERAND (mips_opts.micromips,
 
                          3BITPOS, insn, va_arg (args, unsigned int));
 
          continue;
 
 
 
        case '~':
 
          INSERT_OPERAND (mips_opts.micromips,
 
                          OFFSET12, insn, va_arg (args, unsigned long));
 
          continue;
 
 
 
        case 'N':
 
          gas_assert (mips_opts.micromips);
 
          INSERT_OPERAND (1, BCC, insn, va_arg (args, int));
 
          continue;
 
 
 
        case 'm':       /* Opcode extension character.  */
 
          gas_assert (mips_opts.micromips);
 
          switch (*fmt++)
 
            {
 
            case 'j':
 
              INSERT_OPERAND (1, MJ, insn, va_arg (args, int));
 
              break;
 
 
 
            case 'p':
 
              INSERT_OPERAND (1, MP, insn, va_arg (args, int));
 
              break;
 
 
 
            case 'F':
 
              INSERT_OPERAND (1, IMMF, insn, va_arg (args, int));
 
              break;
 
 
 
            default:
 
              internalError ();
 
            }
          continue;
          continue;
 
 
        default:
        default:
          internalError ();
          internalError ();
        }
        }
      break;
      break;
    }
    }
  va_end (args);
  va_end (args);
  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
 
  append_insn (&insn, ep, r);
  append_insn (&insn, ep, r, TRUE);
}
}
 
 
static void
static void
mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
mips16_macro_build (expressionS *ep, const char *name, const char *fmt,
                    va_list *args)
                    va_list *args)
Line 4189... Line 5211...
      break;
      break;
    }
    }
 
 
  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
 
 
  append_insn (&insn, ep, r);
  append_insn (&insn, ep, r, TRUE);
}
}
 
 
/*
/*
 * Sign-extend 32-bit mode constants that have bit 31 set and all
 * Sign-extend 32-bit mode constants that have bit 31 set and all
 * higher bits unset.
 * higher bits unset.
Line 4224... Line 5246...
/*
/*
 * Generate a "jalr" instruction with a relocation hint to the called
 * Generate a "jalr" instruction with a relocation hint to the called
 * function.  This occurs in NewABI PIC code.
 * function.  This occurs in NewABI PIC code.
 */
 */
static void
static void
macro_build_jalr (expressionS *ep)
macro_build_jalr (expressionS *ep, int cprestore)
{
{
 
  static const bfd_reloc_code_real_type jalr_relocs[2]
 
    = { BFD_RELOC_MIPS_JALR, BFD_RELOC_MICROMIPS_JALR };
 
  bfd_reloc_code_real_type jalr_reloc = jalr_relocs[mips_opts.micromips];
 
  const char *jalr;
  char *f = NULL;
  char *f = NULL;
 
 
  if (MIPS_JALR_HINT_P (ep))
  if (MIPS_JALR_HINT_P (ep))
    {
    {
      frag_grow (8);
      frag_grow (8);
      f = frag_more (0);
      f = frag_more (0);
    }
    }
 
  if (!mips_opts.micromips)
  macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
  macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
 
  else
 
    {
 
      jalr = mips_opts.noreorder && !cprestore ? "jalr" : "jalrs";
 
      if (MIPS_JALR_HINT_P (ep))
 
        macro_build (NULL, jalr, "t,s", RA, PIC_CALL_REG);
 
      else
 
        macro_build (NULL, jalr, "mj", PIC_CALL_REG);
 
    }
  if (MIPS_JALR_HINT_P (ep))
  if (MIPS_JALR_HINT_P (ep))
    fix_new_exp (frag_now, f - frag_now->fr_literal,
    fix_new_exp (frag_now, f - frag_now->fr_literal, 4, ep, FALSE, jalr_reloc);
                 4, ep, FALSE, BFD_RELOC_MIPS_JALR);
 
}
}
 
 
/*
/*
 * Generate a "lui" instruction.
 * Generate a "lui" instruction.
 */
 */
static void
static void
macro_build_lui (expressionS *ep, int regnum)
macro_build_lui (expressionS *ep, int regnum)
{
{
  expressionS high_expr;
 
  const struct mips_opcode *mo;
 
  struct mips_cl_insn insn;
 
  bfd_reloc_code_real_type r[3]
 
    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 
  const char *name = "lui";
 
  const char *fmt = "t,u";
 
 
 
  gas_assert (! mips_opts.mips16);
  gas_assert (! mips_opts.mips16);
 
 
  high_expr = *ep;
  if (ep->X_op != O_constant)
 
 
  if (high_expr.X_op == O_constant)
 
    {
 
      /* We can compute the instruction now without a relocation entry.  */
 
      high_expr.X_add_number = ((high_expr.X_add_number + 0x8000)
 
                                >> 16) & 0xffff;
 
      *r = BFD_RELOC_UNUSED;
 
    }
 
  else
 
    {
    {
      gas_assert (ep->X_op == O_symbol);
      gas_assert (ep->X_op == O_symbol);
      /* _gp_disp is a special case, used from s_cpload.
      /* _gp_disp is a special case, used from s_cpload.
         __gnu_local_gp is used if mips_no_shared.  */
         __gnu_local_gp is used if mips_no_shared.  */
      gas_assert (mips_pic == NO_PIC
      gas_assert (mips_pic == NO_PIC
              || (! HAVE_NEWABI
              || (! HAVE_NEWABI
                  && strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
                  && strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
              || (! mips_in_shared
              || (! mips_in_shared
                  && strcmp (S_GET_NAME (ep->X_add_symbol),
                  && strcmp (S_GET_NAME (ep->X_add_symbol),
                             "__gnu_local_gp") == 0));
                             "__gnu_local_gp") == 0));
      *r = BFD_RELOC_HI16_S;
 
    }
    }
 
 
  mo = hash_find (op_hash, name);
  macro_build (ep, "lui", LUI_FMT, regnum, BFD_RELOC_HI16_S);
  gas_assert (strcmp (name, mo->name) == 0);
 
  gas_assert (strcmp (fmt, mo->args) == 0);
 
  create_insn (&insn, mo);
 
 
 
  insn.insn_opcode = insn.insn_mo->match;
 
  INSERT_OPERAND (RT, insn, regnum);
 
  if (*r == BFD_RELOC_UNUSED)
 
    {
 
      insn.insn_opcode |= high_expr.X_add_number;
 
      append_insn (&insn, NULL, r);
 
    }
 
  else
 
    append_insn (&insn, &high_expr, r);
 
}
}
 
 
/* Generate a sequence of instructions to do a load or store from a constant
/* Generate a sequence of instructions to do a load or store from a constant
   offset off of a base register (breg) into/from a target register (treg),
   offset off of a base register (breg) into/from a target register (treg),
   using AT if necessary.  */
   using AT if necessary.  */
Line 4478... Line 5481...
          return;
          return;
        }
        }
      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
        {
        {
          /* 32 bit values require an lui.  */
          /* 32 bit values require an lui.  */
          macro_build (ep, "lui", "t,u", reg, BFD_RELOC_HI16);
          macro_build (ep, "lui", LUI_FMT, reg, BFD_RELOC_HI16);
          if ((ep->X_add_number & 0xffff) != 0)
          if ((ep->X_add_number & 0xffff) != 0)
            macro_build (ep, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
            macro_build (ep, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
          return;
          return;
        }
        }
    }
    }
Line 4535... Line 5538...
              macro_build (&lo32, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
              macro_build (&lo32, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
              return;
              return;
            }
            }
          if (lo32.X_add_number & 0x80000000)
          if (lo32.X_add_number & 0x80000000)
            {
            {
              macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
              macro_build (&lo32, "lui", LUI_FMT, reg, BFD_RELOC_HI16);
              if (lo32.X_add_number & 0xffff)
              if (lo32.X_add_number & 0xffff)
                macro_build (&lo32, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
                macro_build (&lo32, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
              return;
              return;
            }
            }
        }
        }
Line 4572... Line 5575...
                tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
                tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
                                    | (lo32.X_add_number >> shift));
                                    | (lo32.X_add_number >> shift));
              else
              else
                tmp.X_add_number = hi32.X_add_number >> (shift - 32);
                tmp.X_add_number = hi32.X_add_number >> (shift - 32);
              macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
              macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
              macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
              macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", SHFT_FMT,
                           reg, reg, (shift >= 32) ? shift - 32 : shift);
                           reg, reg, (shift >= 32) ? shift - 32 : shift);
              return;
              return;
            }
            }
          ++shift;
          ++shift;
        }
        }
Line 4624... Line 5627...
              tmp.X_add_number = (offsetT) -1;
              tmp.X_add_number = (offsetT) -1;
              macro_build (&tmp, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
              macro_build (&tmp, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
              if (bit != 0)
              if (bit != 0)
                {
                {
                  bit += shift;
                  bit += shift;
                  macro_build (NULL, (bit >= 32) ? "dsll32" : "dsll", "d,w,<",
                  macro_build (NULL, (bit >= 32) ? "dsll32" : "dsll", SHFT_FMT,
                               reg, reg, (bit >= 32) ? bit - 32 : bit);
                               reg, reg, (bit >= 32) ? bit - 32 : bit);
                }
                }
              macro_build (NULL, (shift >= 32) ? "dsrl32" : "dsrl", "d,w,<",
              macro_build (NULL, (shift >= 32) ? "dsrl32" : "dsrl", SHFT_FMT,
                           reg, reg, (shift >= 32) ? shift - 32 : shift);
                           reg, reg, (shift >= 32) ? shift - 32 : shift);
              return;
              return;
            }
            }
        }
        }
 
 
Line 4644... Line 5647...
    }
    }
  if ((lo32.X_add_number & 0xffff0000) == 0)
  if ((lo32.X_add_number & 0xffff0000) == 0)
    {
    {
      if (freg != 0)
      if (freg != 0)
        {
        {
          macro_build (NULL, "dsll32", "d,w,<", reg, freg, 0);
          macro_build (NULL, "dsll32", SHFT_FMT, reg, freg, 0);
          freg = reg;
          freg = reg;
        }
        }
    }
    }
  else
  else
    {
    {
      expressionS mid16;
      expressionS mid16;
 
 
      if ((freg == 0) && (lo32.X_add_number == (offsetT) 0xffffffff))
      if ((freg == 0) && (lo32.X_add_number == (offsetT) 0xffffffff))
        {
        {
          macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
          macro_build (&lo32, "lui", LUI_FMT, reg, BFD_RELOC_HI16);
          macro_build (NULL, "dsrl32", "d,w,<", reg, reg, 0);
          macro_build (NULL, "dsrl32", SHFT_FMT, reg, reg, 0);
          return;
          return;
        }
        }
 
 
      if (freg != 0)
      if (freg != 0)
        {
        {
          macro_build (NULL, "dsll", "d,w,<", reg, freg, 16);
          macro_build (NULL, "dsll", SHFT_FMT, reg, freg, 16);
          freg = reg;
          freg = reg;
        }
        }
      mid16 = lo32;
      mid16 = lo32;
      mid16.X_add_number >>= 16;
      mid16.X_add_number >>= 16;
      macro_build (&mid16, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
      macro_build (&mid16, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
      macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
      macro_build (NULL, "dsll", SHFT_FMT, reg, reg, 16);
      freg = reg;
      freg = reg;
    }
    }
  if ((lo32.X_add_number & 0xffff) != 0)
  if ((lo32.X_add_number & 0xffff) != 0)
    macro_build (&lo32, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
    macro_build (&lo32, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
}
}
Line 4740... Line 5743...
              relax_switch ();
              relax_switch ();
            }
            }
 
 
          if (*used_at == 0 && mips_opts.at)
          if (*used_at == 0 && mips_opts.at)
            {
            {
              macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
              macro_build (ep, "lui", LUI_FMT, reg, BFD_RELOC_MIPS_HIGHEST);
              macro_build (ep, "lui", "t,u", AT, BFD_RELOC_HI16_S);
              macro_build (ep, "lui", LUI_FMT, AT, BFD_RELOC_HI16_S);
              macro_build (ep, "daddiu", "t,r,j", reg, reg,
              macro_build (ep, "daddiu", "t,r,j", reg, reg,
                           BFD_RELOC_MIPS_HIGHER);
                           BFD_RELOC_MIPS_HIGHER);
              macro_build (ep, "daddiu", "t,r,j", AT, AT, BFD_RELOC_LO16);
              macro_build (ep, "daddiu", "t,r,j", AT, AT, BFD_RELOC_LO16);
              macro_build (NULL, "dsll32", "d,w,<", reg, reg, 0);
              macro_build (NULL, "dsll32", SHFT_FMT, reg, reg, 0);
              macro_build (NULL, "daddu", "d,v,t", reg, reg, AT);
              macro_build (NULL, "daddu", "d,v,t", reg, reg, AT);
              *used_at = 1;
              *used_at = 1;
            }
            }
          else
          else
            {
            {
              macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
              macro_build (ep, "lui", LUI_FMT, reg, BFD_RELOC_MIPS_HIGHEST);
              macro_build (ep, "daddiu", "t,r,j", reg, reg,
              macro_build (ep, "daddiu", "t,r,j", reg, reg,
                           BFD_RELOC_MIPS_HIGHER);
                           BFD_RELOC_MIPS_HIGHER);
              macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
              macro_build (NULL, "dsll", SHFT_FMT, reg, reg, 16);
              macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_HI16_S);
              macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_HI16_S);
              macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
              macro_build (NULL, "dsll", SHFT_FMT, reg, reg, 16);
              macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_LO16);
              macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_LO16);
            }
            }
 
 
          if (mips_relax.sequence)
          if (mips_relax.sequence)
            relax_end ();
            relax_end ();
Line 4866... Line 5869...
      if (HAVE_NEWABI)
      if (HAVE_NEWABI)
        {
        {
          ex.X_add_number = ep->X_add_number;
          ex.X_add_number = ep->X_add_number;
          ep->X_add_number = 0;
          ep->X_add_number = 0;
          relax_start (ep->X_add_symbol);
          relax_start (ep->X_add_symbol);
          macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
          macro_build (ep, "lui", LUI_FMT, reg, BFD_RELOC_MIPS_GOT_HI16);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       reg, reg, mips_gp_register);
                       reg, reg, mips_gp_register);
          macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
          macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
                       reg, BFD_RELOC_MIPS_GOT_LO16, reg);
                       reg, BFD_RELOC_MIPS_GOT_LO16, reg);
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
          if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
Line 4893... Line 5896...
      else
      else
        {
        {
          ex.X_add_number = ep->X_add_number;
          ex.X_add_number = ep->X_add_number;
          ep->X_add_number = 0;
          ep->X_add_number = 0;
          relax_start (ep->X_add_symbol);
          relax_start (ep->X_add_symbol);
          macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
          macro_build (ep, "lui", LUI_FMT, reg, BFD_RELOC_MIPS_GOT_HI16);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       reg, reg, mips_gp_register);
                       reg, reg, mips_gp_register);
          macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
          macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
                       reg, BFD_RELOC_MIPS_GOT_LO16, reg);
                       reg, BFD_RELOC_MIPS_GOT_LO16, reg);
          relax_switch ();
          relax_switch ();
Line 4936... Line 5939...
/* Move the contents of register SOURCE into register DEST.  */
/* Move the contents of register SOURCE into register DEST.  */
 
 
static void
static void
move_register (int dest, int source)
move_register (int dest, int source)
{
{
 
  /* Prefer to use a 16-bit microMIPS instruction unless the previous
 
     instruction specifically requires a 32-bit one.  */
 
  if (mips_opts.micromips
 
      && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
 
    macro_build (NULL, "move", "mp,mj", dest, source );
 
  else
  macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
  macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
               dest, source, 0);
               dest, source, 0);
}
}
 
 
/* Emit an SVR4 PIC sequence to load address LOCAL into DEST, where
/* Emit an SVR4 PIC sequence to load address LOCAL into DEST, where
Line 5015... Line 6024...
  relax_end ();
  relax_end ();
 
 
  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dest, dest, tmp);
  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dest, dest, tmp);
}
}
 
 
 
/* Emit a sequence of instructions to emulate a branch likely operation.
 
   BR is an ordinary branch corresponding to one to be emulated.  BRNEG
 
   is its complementing branch with the original condition negated.
 
   CALL is set if the original branch specified the link operation.
 
   EP, FMT, SREG and TREG specify the usual macro_build() parameters.
 
 
 
   Code like this is produced in the noreorder mode:
 
 
 
        BRNEG   <args>, 1f
 
         nop
 
        b       <sym>
 
         delay slot (executed only if branch taken)
 
    1:
 
 
 
   or, if CALL is set:
 
 
 
        BRNEG   <args>, 1f
 
         nop
 
        bal     <sym>
 
         delay slot (executed only if branch taken)
 
    1:
 
 
 
   In the reorder mode the delay slot would be filled with a nop anyway,
 
   so code produced is simply:
 
 
 
        BR      <args>, <sym>
 
         nop
 
 
 
   This function is used when producing code for the microMIPS ASE that
 
   does not implement branch likely instructions in hardware.  */
 
 
 
static void
 
macro_build_branch_likely (const char *br, const char *brneg,
 
                           int call, expressionS *ep, const char *fmt,
 
                           unsigned int sreg, unsigned int treg)
 
{
 
  int noreorder = mips_opts.noreorder;
 
  expressionS expr1;
 
 
 
  gas_assert (mips_opts.micromips);
 
  start_noreorder ();
 
  if (noreorder)
 
    {
 
      micromips_label_expr (&expr1);
 
      macro_build (&expr1, brneg, fmt, sreg, treg);
 
      macro_build (NULL, "nop", "");
 
      macro_build (ep, call ? "bal" : "b", "p");
 
 
 
      /* Set to true so that append_insn adds a label.  */
 
      emit_branch_likely_macro = TRUE;
 
    }
 
  else
 
    {
 
      macro_build (ep, br, fmt, sreg, treg);
 
      macro_build (NULL, "nop", "");
 
    }
 
  end_noreorder ();
 
}
 
 
 
/* Emit a coprocessor branch-likely macro specified by TYPE, using CC as
 
   the condition code tested.  EP specifies the branch target.  */
 
 
 
static void
 
macro_build_branch_ccl (int type, expressionS *ep, unsigned int cc)
 
{
 
  const int call = 0;
 
  const char *brneg;
 
  const char *br;
 
 
 
  switch (type)
 
    {
 
    case M_BC1FL:
 
      br = "bc1f";
 
      brneg = "bc1t";
 
      break;
 
    case M_BC1TL:
 
      br = "bc1t";
 
      brneg = "bc1f";
 
      break;
 
    case M_BC2FL:
 
      br = "bc2f";
 
      brneg = "bc2t";
 
      break;
 
    case M_BC2TL:
 
      br = "bc2t";
 
      brneg = "bc2f";
 
      break;
 
    default:
 
      abort ();
 
    }
 
  macro_build_branch_likely (br, brneg, call, ep, "N,p", cc, ZERO);
 
}
 
 
 
/* Emit a two-argument branch macro specified by TYPE, using SREG as
 
   the register tested.  EP specifies the branch target.  */
 
 
 
static void
 
macro_build_branch_rs (int type, expressionS *ep, unsigned int sreg)
 
{
 
  const char *brneg = NULL;
 
  const char *br;
 
  int call = 0;
 
 
 
  switch (type)
 
    {
 
    case M_BGEZ:
 
      br = "bgez";
 
      break;
 
    case M_BGEZL:
 
      br = mips_opts.micromips ? "bgez" : "bgezl";
 
      brneg = "bltz";
 
      break;
 
    case M_BGEZALL:
 
      gas_assert (mips_opts.micromips);
 
      br = "bgezals";
 
      brneg = "bltz";
 
      call = 1;
 
      break;
 
    case M_BGTZ:
 
      br = "bgtz";
 
      break;
 
    case M_BGTZL:
 
      br = mips_opts.micromips ? "bgtz" : "bgtzl";
 
      brneg = "blez";
 
      break;
 
    case M_BLEZ:
 
      br = "blez";
 
      break;
 
    case M_BLEZL:
 
      br = mips_opts.micromips ? "blez" : "blezl";
 
      brneg = "bgtz";
 
      break;
 
    case M_BLTZ:
 
      br = "bltz";
 
      break;
 
    case M_BLTZL:
 
      br = mips_opts.micromips ? "bltz" : "bltzl";
 
      brneg = "bgez";
 
      break;
 
    case M_BLTZALL:
 
      gas_assert (mips_opts.micromips);
 
      br = "bltzals";
 
      brneg = "bgez";
 
      call = 1;
 
      break;
 
    default:
 
      abort ();
 
    }
 
  if (mips_opts.micromips && brneg)
 
    macro_build_branch_likely (br, brneg, call, ep, "s,p", sreg, ZERO);
 
  else
 
    macro_build (ep, br, "s,p", sreg);
 
}
 
 
 
/* Emit a three-argument branch macro specified by TYPE, using SREG and
 
   TREG as the registers tested.  EP specifies the branch target.  */
 
 
 
static void
 
macro_build_branch_rsrt (int type, expressionS *ep,
 
                         unsigned int sreg, unsigned int treg)
 
{
 
  const char *brneg = NULL;
 
  const int call = 0;
 
  const char *br;
 
 
 
  switch (type)
 
    {
 
    case M_BEQ:
 
    case M_BEQ_I:
 
      br = "beq";
 
      break;
 
    case M_BEQL:
 
    case M_BEQL_I:
 
      br = mips_opts.micromips ? "beq" : "beql";
 
      brneg = "bne";
 
      break;
 
    case M_BNE:
 
    case M_BNE_I:
 
      br = "bne";
 
      break;
 
    case M_BNEL:
 
    case M_BNEL_I:
 
      br = mips_opts.micromips ? "bne" : "bnel";
 
      brneg = "beq";
 
      break;
 
    default:
 
      abort ();
 
    }
 
  if (mips_opts.micromips && brneg)
 
    macro_build_branch_likely (br, brneg, call, ep, "s,t,p", sreg, treg);
 
  else
 
    macro_build (ep, br, "s,t,p", sreg, treg);
 
}
 
 
/*
/*
 *                      Build macros
 *                      Build macros
 *   This routine implements the seemingly endless macro or synthesized
 *   This routine implements the seemingly endless macro or synthesized
 * instructions and addressing modes in the mips assembly language. Many
 * instructions and addressing modes in the mips assembly language. Many
 * of these macros are simple and are similar to each other. These could
 * of these macros are simple and are similar to each other. These could
Line 5040... Line 6243...
{
{
  unsigned int treg, sreg, dreg, breg;
  unsigned int treg, sreg, dreg, breg;
  unsigned int tempreg;
  unsigned int tempreg;
  int mask;
  int mask;
  int used_at = 0;
  int used_at = 0;
 
  expressionS label_expr;
  expressionS expr1;
  expressionS expr1;
 
  expressionS *ep;
  const char *s;
  const char *s;
  const char *s2;
  const char *s2;
  const char *fmt;
  const char *fmt;
  int likely = 0;
  int likely = 0;
  int dbl = 0;
 
  int coproc = 0;
  int coproc = 0;
  int lr = 0;
  int off12 = 0;
  int imm = 0;
 
  int call = 0;
  int call = 0;
 
  int jals = 0;
 
  int dbl = 0;
 
  int imm = 0;
 
  int ust = 0;
 
  int lp = 0;
 
  int ab = 0;
  int off;
  int off;
  offsetT maxnum;
  offsetT maxnum;
  bfd_reloc_code_real_type r;
  bfd_reloc_code_real_type r;
  int hold_mips_optimize;
  int hold_mips_optimize;
 
 
  gas_assert (! mips_opts.mips16);
  gas_assert (! mips_opts.mips16);
 
 
  treg = EXTRACT_OPERAND (RT, *ip);
  treg = EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
  dreg = EXTRACT_OPERAND (RD, *ip);
  dreg = EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
  sreg = breg = EXTRACT_OPERAND (RS, *ip);
  sreg = breg = EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
  mask = ip->insn_mo->mask;
  mask = ip->insn_mo->mask;
 
 
 
  label_expr.X_op = O_constant;
 
  label_expr.X_op_symbol = NULL;
 
  label_expr.X_add_symbol = NULL;
 
  label_expr.X_add_number = 0;
 
 
  expr1.X_op = O_constant;
  expr1.X_op = O_constant;
  expr1.X_op_symbol = NULL;
  expr1.X_op_symbol = NULL;
  expr1.X_add_symbol = NULL;
  expr1.X_add_symbol = NULL;
  expr1.X_add_number = 1;
  expr1.X_add_number = 1;
 
 
  switch (mask)
  switch (mask)
    {
    {
    case M_DABS:
    case M_DABS:
      dbl = 1;
      dbl = 1;
    case M_ABS:
    case M_ABS:
      /* bgez $a0,.+12
      /*    bgez    $a0,1f
         move v0,$a0
         move v0,$a0
         sub v0,$zero,$a0
         sub v0,$zero,$a0
 
         1:
         */
         */
 
 
      start_noreorder ();
      start_noreorder ();
 
 
      expr1.X_add_number = 8;
      if (mips_opts.micromips)
      macro_build (&expr1, "bgez", "s,p", sreg);
        micromips_label_expr (&label_expr);
 
      else
 
        label_expr.X_add_number = 8;
 
      macro_build (&label_expr, "bgez", "s,p", sreg);
      if (dreg == sreg)
      if (dreg == sreg)
        macro_build (NULL, "nop", "");
        macro_build (NULL, "nop", "");
      else
      else
        move_register (dreg, sreg);
        move_register (dreg, sreg);
      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
 
      if (mips_opts.micromips)
 
        micromips_add_label ();
 
 
      end_noreorder ();
      end_noreorder ();
      break;
      break;
 
 
    case M_ADD_I:
    case M_ADD_I:
Line 5102... Line 6322...
      goto do_addi;
      goto do_addi;
    case M_DADD_I:
    case M_DADD_I:
      dbl = 1;
      dbl = 1;
      s = "daddi";
      s = "daddi";
      s2 = "dadd";
      s2 = "dadd";
 
      if (!mips_opts.micromips)
      goto do_addi;
      goto do_addi;
 
      if (imm_expr.X_op == O_constant
 
          && imm_expr.X_add_number >= -0x200
 
          && imm_expr.X_add_number < 0x200)
 
        {
 
          macro_build (NULL, s, "t,r,.", treg, sreg, imm_expr.X_add_number);
 
          break;
 
        }
 
      goto do_addi_i;
    case M_DADDU_I:
    case M_DADDU_I:
      dbl = 1;
      dbl = 1;
      s = "daddiu";
      s = "daddiu";
      s2 = "daddu";
      s2 = "daddu";
    do_addi:
    do_addi:
Line 5115... Line 6344...
          && 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);
          macro_build (&imm_expr, s, "t,r,j", treg, sreg, BFD_RELOC_LO16);
          break;
          break;
        }
        }
 
    do_addi_i:
      used_at = 1;
      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
      break;
      break;
 
 
Line 5172... Line 6402...
                       (int) imm_expr.X_add_number);
                       (int) imm_expr.X_add_number);
          break;
          break;
        }
        }
      break;
      break;
 
 
 
    case M_BC1FL:
 
    case M_BC1TL:
 
    case M_BC2FL:
 
    case M_BC2TL:
 
      gas_assert (mips_opts.micromips);
 
      macro_build_branch_ccl (mask, &offset_expr,
 
                              EXTRACT_OPERAND (1, BCC, *ip));
 
      break;
 
 
    case M_BEQ_I:
    case M_BEQ_I:
      s = "beq";
 
      goto beq_i;
 
    case M_BEQL_I:
    case M_BEQL_I:
      s = "beql";
 
      likely = 1;
 
      goto beq_i;
 
    case M_BNE_I:
    case M_BNE_I:
      s = "bne";
 
      goto beq_i;
 
    case M_BNEL_I:
    case M_BNEL_I:
      s = "bnel";
 
      likely = 1;
 
    beq_i:
 
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
 
        treg = 0;
 
      else
        {
        {
          macro_build (&offset_expr, s, "s,t,p", sreg, ZERO);
          treg = AT;
          break;
 
        }
 
      used_at = 1;
      used_at = 1;
      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
          load_register (treg, &imm_expr, HAVE_64BIT_GPRS);
      macro_build (&offset_expr, s, "s,t,p", sreg, AT);
        }
 
      /* Fall through.  */
 
    case M_BEQL:
 
    case M_BNEL:
 
      macro_build_branch_rsrt (mask, &offset_expr, sreg, treg);
      break;
      break;
 
 
    case M_BGEL:
    case M_BGEL:
      likely = 1;
      likely = 1;
    case M_BGE:
    case M_BGE:
      if (treg == 0)
      if (treg == 0)
 
        macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, sreg);
 
      else if (sreg == 0)
 
        macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, treg);
 
      else
        {
        {
          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;
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                   &offset_expr, AT, ZERO);
 
        }
 
      break;
 
 
 
    case M_BGEZL:
 
    case M_BGEZALL:
 
    case M_BGTZL:
 
    case M_BLEZL:
 
    case M_BLTZL:
 
    case M_BLTZALL:
 
      macro_build_branch_rs (mask, &offset_expr, sreg);
      break;
      break;
 
 
    case M_BGTL_I:
    case M_BGTL_I:
      likely = 1;
      likely = 1;
    case M_BGT_I:
    case M_BGT_I:
Line 5235... Line 6475...
        do_false:
        do_false:
          /* Result is always false.  */
          /* Result is always false.  */
          if (! likely)
          if (! likely)
            macro_build (NULL, "nop", "");
            macro_build (NULL, "nop", "");
          else
          else
            macro_build (&offset_expr, "bnel", "s,t,p", ZERO, ZERO);
            macro_build_branch_rsrt (M_BNEL, &offset_expr, ZERO, ZERO);
          break;
          break;
        }
        }
      if (imm_expr.X_op != O_constant)
      if (imm_expr.X_op != O_constant)
        as_bad (_("Unsupported large constant"));
        as_bad (_("Unsupported large constant"));
      ++imm_expr.X_add_number;
      ++imm_expr.X_add_number;
Line 5248... Line 6488...
    case M_BGEL_I:
    case M_BGEL_I:
      if (mask == M_BGEL_I)
      if (mask == M_BGEL_I)
        likely = 1;
        likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
        {
          macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
          macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ,
 
                                 &offset_expr, sreg);
          break;
          break;
        }
        }
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
        {
          macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
          macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ,
 
                                 &offset_expr, sreg);
          break;
          break;
        }
        }
      maxnum = 0x7fffffff;
      maxnum = 0x7fffffff;
      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
        {
        {
Line 5277... Line 6519...
          macro_build (&offset_expr, "b", "p");
          macro_build (&offset_expr, "b", "p");
          break;
          break;
        }
        }
      used_at = 1;
      used_at = 1;
      set_at (sreg, 0);
      set_at (sreg, 0);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
      macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                               &offset_expr, AT, ZERO);
      break;
      break;
 
 
    case M_BGEUL:
    case M_BGEUL:
      likely = 1;
      likely = 1;
    case M_BGEU:
    case M_BGEU:
      if (treg == 0)
      if (treg == 0)
        goto do_true;
        goto do_true;
      if (sreg == 0)
      else if (sreg == 0)
 
        macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                 &offset_expr, ZERO, treg);
 
      else
        {
        {
          macro_build (&offset_expr, likely ? "beql" : "beq",
 
                       "s,t,p", ZERO, treg);
 
          break;
 
        }
 
      used_at = 1;
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BGTUL_I:
    case M_BGTUL_I:
      likely = 1;
      likely = 1;
    case M_BGTU_I:
    case M_BGTU_I:
Line 5314... Line 6558...
    case M_BGEUL_I:
    case M_BGEUL_I:
      if (mask == M_BGEUL_I)
      if (mask == M_BGEUL_I)
        likely = 1;
        likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        goto do_true;
        goto do_true;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
      else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
 
        macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                 &offset_expr, sreg, ZERO);
 
      else
        {
        {
          macro_build (&offset_expr, likely ? "bnel" : "bne",
 
                       "s,t,p", sreg, ZERO);
 
          break;
 
        }
 
      used_at = 1;
      used_at = 1;
      set_at (sreg, 1);
      set_at (sreg, 1);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BGTL:
    case M_BGTL:
      likely = 1;
      likely = 1;
    case M_BGT:
    case M_BGT:
      if (treg == 0)
      if (treg == 0)
 
        macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, sreg);
 
      else if (sreg == 0)
 
        macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, treg);
 
      else
        {
        {
          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;
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BGTUL:
    case M_BGTUL:
      likely = 1;
      likely = 1;
    case M_BGTU:
    case M_BGTU:
      if (treg == 0)
      if (treg == 0)
        {
        macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
          macro_build (&offset_expr, likely ? "bnel" : "bne",
                                 &offset_expr, sreg, ZERO);
                       "s,t,p", sreg, ZERO);
      else if (sreg == 0)
          break;
 
        }
 
      if (sreg == 0)
 
        goto do_false;
        goto do_false;
 
      else
 
        {
      used_at = 1;
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BLEL:
    case M_BLEL:
      likely = 1;
      likely = 1;
    case M_BLE:
    case M_BLE:
      if (treg == 0)
      if (treg == 0)
 
        macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, sreg);
 
      else if (sreg == 0)
 
        macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, treg);
 
      else
        {
        {
          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;
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BLEL_I:
    case M_BLEL_I:
      likely = 1;
      likely = 1;
    case M_BLE_I:
    case M_BLE_I:
Line 5401... Line 6643...
    case M_BLT_I:
    case M_BLT_I:
    case M_BLTL_I:
    case M_BLTL_I:
      if (mask == M_BLTL_I)
      if (mask == M_BLTL_I)
        likely = 1;
        likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
 
        macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, sreg);
 
      else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
 
        macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, sreg);
 
      else
        {
        {
          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;
      used_at = 1;
      set_at (sreg, 0);
      set_at (sreg, 0);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BLEUL:
    case M_BLEUL:
      likely = 1;
      likely = 1;
    case M_BLEU:
    case M_BLEU:
      if (treg == 0)
      if (treg == 0)
 
        macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                 &offset_expr, sreg, ZERO);
 
      else if (sreg == 0)
 
        goto do_true;
 
      else
        {
        {
          macro_build (&offset_expr, likely ? "beql" : "beq",
 
                       "s,t,p", sreg, ZERO);
 
          break;
 
        }
 
      if (sreg == 0)
 
        goto do_true;
 
      used_at = 1;
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BLEUL_I:
    case M_BLEUL_I:
      likely = 1;
      likely = 1;
    case M_BLEU_I:
    case M_BLEU_I:
Line 5449... Line 6690...
    case M_BLTUL_I:
    case M_BLTUL_I:
      if (mask == M_BLTUL_I)
      if (mask == M_BLTUL_I)
        likely = 1;
        likely = 1;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        goto do_false;
        goto do_false;
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
      else if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
 
        macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ,
 
                                 &offset_expr, sreg, ZERO);
 
      else
        {
        {
          macro_build (&offset_expr, likely ? "beql" : "beq",
 
                       "s,t,p", sreg, ZERO);
 
          break;
 
        }
 
      used_at = 1;
      used_at = 1;
      set_at (sreg, 1);
      set_at (sreg, 1);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BLTL:
    case M_BLTL:
      likely = 1;
      likely = 1;
    case M_BLT:
    case M_BLT:
      if (treg == 0)
      if (treg == 0)
 
        macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, sreg);
 
      else if (sreg == 0)
 
        macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, treg);
 
      else
        {
        {
          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;
      used_at = 1;
      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_BLTUL:
    case M_BLTUL:
      likely = 1;
      likely = 1;
    case M_BLTU:
    case M_BLTU:
      if (treg == 0)
      if (treg == 0)
        goto do_false;
        goto do_false;
      if (sreg == 0)
      else if (sreg == 0)
 
        macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                 &offset_expr, ZERO, treg);
 
      else
        {
        {
          macro_build (&offset_expr, likely ? "bnel" : "bne",
 
                       "s,t,p", ZERO, treg);
 
          break;
 
        }
 
      used_at = 1;
      used_at = 1;
      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, ZERO);
          macro_build_branch_rsrt (likely ? M_BNEL : M_BNE,
 
                                   &offset_expr, AT, ZERO);
 
        }
      break;
      break;
 
 
    case M_DEXT:
    case M_DEXT:
      {
      {
        /* Use unsigned arithmetic.  */
        /* Use unsigned arithmetic.  */
Line 5606... Line 6847...
    do_div3:
    do_div3:
      if (treg == 0)
      if (treg == 0)
        {
        {
          as_warn (_("Divide by zero."));
          as_warn (_("Divide by zero."));
          if (mips_trap)
          if (mips_trap)
            macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
            macro_build (NULL, "teq", TRAP_FMT, ZERO, ZERO, 7);
          else
          else
            macro_build (NULL, "break", "c", 7);
            macro_build (NULL, "break", BRK_FMT, 7);
          break;
          break;
        }
        }
 
 
      start_noreorder ();
      start_noreorder ();
      if (mips_trap)
      if (mips_trap)
        {
        {
          macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
          macro_build (NULL, "teq", TRAP_FMT, treg, ZERO, 7);
          macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
          macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
        }
        }
      else
      else
        {
        {
          expr1.X_add_number = 8;
          if (mips_opts.micromips)
          macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
            micromips_label_expr (&label_expr);
 
          else
 
            label_expr.X_add_number = 8;
 
          macro_build (&label_expr, "bne", "s,t,p", treg, ZERO);
          macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
          macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
          macro_build (NULL, "break", "c", 7);
          macro_build (NULL, "break", BRK_FMT, 7);
 
          if (mips_opts.micromips)
 
            micromips_add_label ();
        }
        }
      expr1.X_add_number = -1;
      expr1.X_add_number = -1;
      used_at = 1;
      used_at = 1;
      load_register (AT, &expr1, dbl);
      load_register (AT, &expr1, dbl);
      expr1.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
      if (mips_opts.micromips)
      macro_build (&expr1, "bne", "s,t,p", treg, AT);
        micromips_label_expr (&label_expr);
 
      else
 
        label_expr.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
 
      macro_build (&label_expr, "bne", "s,t,p", treg, AT);
      if (dbl)
      if (dbl)
        {
        {
          expr1.X_add_number = 1;
          expr1.X_add_number = 1;
          load_register (AT, &expr1, dbl);
          load_register (AT, &expr1, dbl);
          macro_build (NULL, "dsll32", "d,w,<", AT, AT, 31);
          macro_build (NULL, "dsll32", SHFT_FMT, AT, AT, 31);
        }
        }
      else
      else
        {
        {
          expr1.X_add_number = 0x80000000;
          expr1.X_add_number = 0x80000000;
          macro_build (&expr1, "lui", "t,u", AT, BFD_RELOC_HI16);
          macro_build (&expr1, "lui", LUI_FMT, AT, BFD_RELOC_HI16);
        }
        }
      if (mips_trap)
      if (mips_trap)
        {
        {
          macro_build (NULL, "teq", "s,t,q", sreg, AT, 6);
          macro_build (NULL, "teq", TRAP_FMT, sreg, AT, 6);
          /* We want to close the noreorder block as soon as possible, so
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
             that later insns are available for delay slot filling.  */
          end_noreorder ();
          end_noreorder ();
        }
        }
      else
      else
        {
        {
          expr1.X_add_number = 8;
          if (mips_opts.micromips)
          macro_build (&expr1, "bne", "s,t,p", sreg, AT);
            micromips_label_expr (&label_expr);
 
          else
 
            label_expr.X_add_number = 8;
 
          macro_build (&label_expr, "bne", "s,t,p", sreg, AT);
          macro_build (NULL, "nop", "");
          macro_build (NULL, "nop", "");
 
 
          /* We want to close the noreorder block as soon as possible, so
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
             that later insns are available for delay slot filling.  */
          end_noreorder ();
          end_noreorder ();
 
 
          macro_build (NULL, "break", "c", 6);
          macro_build (NULL, "break", BRK_FMT, 6);
        }
        }
      macro_build (NULL, s, "d", dreg);
      if (mips_opts.micromips)
 
        micromips_add_label ();
 
      macro_build (NULL, s, MFHL_FMT, dreg);
      break;
      break;
 
 
    case M_DIV_3I:
    case M_DIV_3I:
      s = "div";
      s = "div";
      s2 = "mflo";
      s2 = "mflo";
Line 5703... Line 6957...
    do_divi:
    do_divi:
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
        {
        {
          as_warn (_("Divide by zero."));
          as_warn (_("Divide by zero."));
          if (mips_trap)
          if (mips_trap)
            macro_build (NULL, "teq", "s,t,q", ZERO, ZERO, 7);
            macro_build (NULL, "teq", TRAP_FMT, ZERO, ZERO, 7);
          else
          else
            macro_build (NULL, "break", "c", 7);
            macro_build (NULL, "break", BRK_FMT, 7);
          break;
          break;
        }
        }
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
        {
        {
          if (strcmp (s2, "mflo") == 0)
          if (strcmp (s2, "mflo") == 0)
Line 5732... Line 6986...
        }
        }
 
 
      used_at = 1;
      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, s, "z,s,t", sreg, AT);
      macro_build (NULL, s, "z,s,t", sreg, AT);
      macro_build (NULL, s2, "d", dreg);
      macro_build (NULL, s2, MFHL_FMT, dreg);
      break;
      break;
 
 
    case M_DIVU_3:
    case M_DIVU_3:
      s = "divu";
      s = "divu";
      s2 = "mflo";
      s2 = "mflo";
Line 5754... Line 7008...
      s2 = "mfhi";
      s2 = "mfhi";
    do_divu3:
    do_divu3:
      start_noreorder ();
      start_noreorder ();
      if (mips_trap)
      if (mips_trap)
        {
        {
          macro_build (NULL, "teq", "s,t,q", treg, ZERO, 7);
          macro_build (NULL, "teq", TRAP_FMT, treg, ZERO, 7);
          macro_build (NULL, s, "z,s,t", sreg, treg);
          macro_build (NULL, s, "z,s,t", sreg, treg);
          /* We want to close the noreorder block as soon as possible, so
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
             that later insns are available for delay slot filling.  */
          end_noreorder ();
          end_noreorder ();
        }
        }
      else
      else
        {
        {
          expr1.X_add_number = 8;
          if (mips_opts.micromips)
          macro_build (&expr1, "bne", "s,t,p", treg, ZERO);
            micromips_label_expr (&label_expr);
 
          else
 
            label_expr.X_add_number = 8;
 
          macro_build (&label_expr, "bne", "s,t,p", treg, ZERO);
          macro_build (NULL, s, "z,s,t", sreg, treg);
          macro_build (NULL, s, "z,s,t", sreg, treg);
 
 
          /* We want to close the noreorder block as soon as possible, so
          /* We want to close the noreorder block as soon as possible, so
             that later insns are available for delay slot filling.  */
             that later insns are available for delay slot filling.  */
          end_noreorder ();
          end_noreorder ();
          macro_build (NULL, "break", "c", 7);
          macro_build (NULL, "break", BRK_FMT, 7);
 
          if (mips_opts.micromips)
 
            micromips_add_label ();
        }
        }
      macro_build (NULL, s2, "d", dreg);
      macro_build (NULL, s2, MFHL_FMT, dreg);
      break;
      break;
 
 
    case M_DLCA_AB:
    case M_DLCA_AB:
      dbl = 1;
      dbl = 1;
    case M_LCA_AB:
    case M_LCA_AB:
Line 5862... Line 7121...
                  relax_switch ();
                  relax_switch ();
                }
                }
 
 
              if (used_at == 0 && mips_opts.at)
              if (used_at == 0 && mips_opts.at)
                {
                {
                  macro_build (&offset_expr, "lui", "t,u",
                  macro_build (&offset_expr, "lui", LUI_FMT,
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
                  macro_build (&offset_expr, "lui", "t,u",
                  macro_build (&offset_expr, "lui", LUI_FMT,
                               AT, BFD_RELOC_HI16_S);
                               AT, BFD_RELOC_HI16_S);
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
                               tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                               AT, AT, BFD_RELOC_LO16);
                               AT, AT, BFD_RELOC_LO16);
                  macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
                  macro_build (NULL, "dsll32", SHFT_FMT, tempreg, tempreg, 0);
                  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                  used_at = 1;
                  used_at = 1;
                }
                }
              else
              else
                {
                {
                  macro_build (&offset_expr, "lui", "t,u",
                  macro_build (&offset_expr, "lui", LUI_FMT,
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
                               tempreg, BFD_RELOC_MIPS_HIGHEST);
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
                               tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
                  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                  macro_build (NULL, "dsll", SHFT_FMT, tempreg, tempreg, 16);
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_HI16_S);
                               tempreg, tempreg, BFD_RELOC_HI16_S);
                  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                  macro_build (NULL, "dsll", SHFT_FMT, tempreg, tempreg, 16);
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                  macro_build (&offset_expr, "daddiu", "t,r,j",
                               tempreg, tempreg, BFD_RELOC_LO16);
                               tempreg, tempreg, BFD_RELOC_LO16);
                }
                }
 
 
              if (mips_relax.sequence)
              if (mips_relax.sequence)
Line 6164... Line 7423...
              && (call || tempreg == PIC_CALL_REG))
              && (call || tempreg == PIC_CALL_REG))
            {
            {
              lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
              lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
            }
            }
          macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
          macro_build (&offset_expr, "lui", LUI_FMT, tempreg, lui_reloc_type);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       tempreg, tempreg, mips_gp_register);
                       tempreg, tempreg, mips_gp_register);
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                       tempreg, lw_reloc_type, tempreg);
                       tempreg, lw_reloc_type, tempreg);
          if (expr1.X_add_number == 0)
          if (expr1.X_add_number == 0)
Line 6309... Line 7568...
              && (call || tempreg == PIC_CALL_REG))
              && (call || tempreg == PIC_CALL_REG))
            {
            {
              lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
              lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
              lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
            }
            }
          macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
          macro_build (&offset_expr, "lui", LUI_FMT, tempreg, lui_reloc_type);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       tempreg, tempreg, mips_gp_register);
                       tempreg, tempreg, mips_gp_register);
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                       tempreg, lw_reloc_type, tempreg);
                       tempreg, lw_reloc_type, tempreg);
 
 
Line 6374... Line 7633...
      if (breg != 0)
      if (breg != 0)
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
      break;
      break;
 
 
    case M_MSGSND:
    case M_MSGSND:
 
      gas_assert (!mips_opts.micromips);
      {
      {
        unsigned long temp = (treg << 16) | (0x01);
        unsigned long temp = (treg << 16) | (0x01);
        macro_build (NULL, "c2", "C", temp);
        macro_build (NULL, "c2", "C", temp);
      }
      }
      break;
      break;
 
 
    case M_MSGLD:
    case M_MSGLD:
 
      gas_assert (!mips_opts.micromips);
      {
      {
        unsigned long temp = (0x02);
        unsigned long temp = (0x02);
        macro_build (NULL, "c2", "C", temp);
        macro_build (NULL, "c2", "C", temp);
      }
      }
      break;
      break;
 
 
    case M_MSGLD_T:
    case M_MSGLD_T:
 
      gas_assert (!mips_opts.micromips);
      {
      {
        unsigned long temp = (treg << 16) | (0x02);
        unsigned long temp = (treg << 16) | (0x02);
        macro_build (NULL, "c2", "C", temp);
        macro_build (NULL, "c2", "C", temp);
      }
      }
      break;
      break;
 
 
    case M_MSGWAIT:
    case M_MSGWAIT:
 
      gas_assert (!mips_opts.micromips);
      macro_build (NULL, "c2", "C", 3);
      macro_build (NULL, "c2", "C", 3);
      break;
      break;
 
 
    case M_MSGWAIT_T:
    case M_MSGWAIT_T:
 
      gas_assert (!mips_opts.micromips);
      {
      {
        unsigned long temp = (treg << 16) | 0x03;
        unsigned long temp = (treg << 16) | 0x03;
        macro_build (NULL, "c2", "C", temp);
        macro_build (NULL, "c2", "C", temp);
      }
      }
      break;
      break;
Line 6418... Line 7682...
      break;
      break;
 
 
      /* The jal instructions must be handled as macros because when
      /* The jal instructions must be handled as macros because when
         generating PIC code they expand to multi-instruction
         generating PIC code they expand to multi-instruction
         sequences.  Normally they are simple instructions.  */
         sequences.  Normally they are simple instructions.  */
 
    case M_JALS_1:
 
      dreg = RA;
 
      /* Fall through.  */
 
    case M_JALS_2:
 
      gas_assert (mips_opts.micromips);
 
      jals = 1;
 
      goto jal;
    case M_JAL_1:
    case M_JAL_1:
      dreg = RA;
      dreg = RA;
      /* Fall through.  */
      /* Fall through.  */
    case M_JAL_2:
    case M_JAL_2:
 
    jal:
      if (mips_pic == NO_PIC)
      if (mips_pic == NO_PIC)
        macro_build (NULL, "jalr", "d,s", dreg, sreg);
        {
 
          s = jals ? "jalrs" : "jalr";
 
          if (mips_opts.micromips && dreg == RA)
 
            macro_build (NULL, s, "mj", sreg);
 
          else
 
            macro_build (NULL, s, JALR_FMT, dreg, sreg);
 
        }
      else
      else
        {
        {
 
          int cprestore = (mips_pic == SVR4_PIC && !HAVE_NEWABI
 
                           && mips_cprestore_offset >= 0);
 
 
          if (sreg != PIC_CALL_REG)
          if (sreg != PIC_CALL_REG)
            as_warn (_("MIPS PIC call to register other than $25"));
            as_warn (_("MIPS PIC call to register other than $25"));
 
 
          macro_build (NULL, "jalr", "d,s", dreg, sreg);
          s = (mips_opts.micromips && (!mips_opts.noreorder || cprestore)
 
               ? "jalrs" : "jalr");
 
          if (mips_opts.micromips && dreg == RA)
 
            macro_build (NULL, s, "mj", sreg);
 
          else
 
            macro_build (NULL, s, JALR_FMT, dreg, sreg);
          if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
          if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
            {
            {
              if (mips_cprestore_offset < 0)
              if (mips_cprestore_offset < 0)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
              else
Line 6461... Line 7747...
            }
            }
        }
        }
 
 
      break;
      break;
 
 
 
    case M_JALS_A:
 
      gas_assert (mips_opts.micromips);
 
      jals = 1;
 
      /* Fall through.  */
    case M_JAL_A:
    case M_JAL_A:
      if (mips_pic == NO_PIC)
      if (mips_pic == NO_PIC)
        macro_build (&offset_expr, "jal", "a");
        macro_build (&offset_expr, jals ? "jals" : "jal", "a");
      else if (mips_pic == SVR4_PIC)
      else if (mips_pic == SVR4_PIC)
        {
        {
          /* If this is a reference to an external symbol, and we are
          /* If this is a reference to an external symbol, and we are
             using a small GOT, we want
             using a small GOT, we want
               lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_CALL16)
               lw       $25,<sym>($gp)          (BFD_RELOC_MIPS_CALL16)
Line 6511... Line 7801...
                  relax_end ();
                  relax_end ();
                }
                }
              else
              else
                {
                {
                  relax_start (offset_expr.X_add_symbol);
                  relax_start (offset_expr.X_add_symbol);
                  macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
                  macro_build (&offset_expr, "lui", LUI_FMT, PIC_CALL_REG,
                               BFD_RELOC_MIPS_CALL_HI16);
                               BFD_RELOC_MIPS_CALL_HI16);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
                               PIC_CALL_REG, mips_gp_register);
                               PIC_CALL_REG, mips_gp_register);
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
Line 6528... Line 7818...
                               PIC_CALL_REG, PIC_CALL_REG,
                               PIC_CALL_REG, PIC_CALL_REG,
                               BFD_RELOC_MIPS_GOT_OFST);
                               BFD_RELOC_MIPS_GOT_OFST);
                  relax_end ();
                  relax_end ();
                }
                }
 
 
              macro_build_jalr (&offset_expr);
              macro_build_jalr (&offset_expr, 0);
            }
            }
          else
          else
            {
            {
              relax_start (offset_expr.X_add_symbol);
              relax_start (offset_expr.X_add_symbol);
              if (!mips_big_got)
              if (!mips_big_got)
Line 6546... Line 7836...
              else
              else
                {
                {
                  int gpdelay;
                  int gpdelay;
 
 
                  gpdelay = reg_needs_delay (mips_gp_register);
                  gpdelay = reg_needs_delay (mips_gp_register);
                  macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
                  macro_build (&offset_expr, "lui", LUI_FMT, PIC_CALL_REG,
                               BFD_RELOC_MIPS_CALL_HI16);
                               BFD_RELOC_MIPS_CALL_HI16);
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
                  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
                               PIC_CALL_REG, mips_gp_register);
                               PIC_CALL_REG, mips_gp_register);
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
                               PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
Line 6565... Line 7855...
                           mips_gp_register);
                           mips_gp_register);
              load_delay_nop ();
              load_delay_nop ();
              macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
              macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
                           PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
                           PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
              relax_end ();
              relax_end ();
              macro_build_jalr (&offset_expr);
              macro_build_jalr (&offset_expr, mips_cprestore_offset >= 0);
 
 
              if (mips_cprestore_offset < 0)
              if (mips_cprestore_offset < 0)
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
                as_warn (_("No .cprestore pseudo-op used in PIC code"));
              else
              else
                {
                {
Line 6600... Line 7890...
      else
      else
        abort ();
        abort ();
 
 
      break;
      break;
 
 
 
    case M_ACLR_AB:
 
      ab = 1;
 
    case M_ACLR_OB:
 
      s = "aclr";
 
      treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
 
      fmt = "\\,~(b)";
 
      off12 = 1;
 
      goto ld_st;
 
    case M_ASET_AB:
 
      ab = 1;
 
    case M_ASET_OB:
 
      s = "aset";
 
      treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
 
      fmt = "\\,~(b)";
 
      off12 = 1;
 
      goto ld_st;
    case M_LB_AB:
    case M_LB_AB:
 
      ab = 1;
      s = "lb";
      s = "lb";
 
      fmt = "t,o(b)";
      goto ld;
      goto ld;
    case M_LBU_AB:
    case M_LBU_AB:
 
      ab = 1;
      s = "lbu";
      s = "lbu";
 
      fmt = "t,o(b)";
      goto ld;
      goto ld;
    case M_LH_AB:
    case M_LH_AB:
 
      ab = 1;
      s = "lh";
      s = "lh";
 
      fmt = "t,o(b)";
      goto ld;
      goto ld;
    case M_LHU_AB:
    case M_LHU_AB:
 
      ab = 1;
      s = "lhu";
      s = "lhu";
 
      fmt = "t,o(b)";
      goto ld;
      goto ld;
    case M_LW_AB:
    case M_LW_AB:
 
      ab = 1;
      s = "lw";
      s = "lw";
 
      fmt = "t,o(b)";
      goto ld;
      goto ld;
    case M_LWC0_AB:
    case M_LWC0_AB:
 
      ab = 1;
 
      gas_assert (!mips_opts.micromips);
      s = "lwc0";
      s = "lwc0";
 
      fmt = "E,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LWC1_AB:
    case M_LWC1_AB:
 
      ab = 1;
      s = "lwc1";
      s = "lwc1";
 
      fmt = "T,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LWC2_AB:
    case M_LWC2_AB:
 
      ab = 1;
 
    case M_LWC2_OB:
      s = "lwc2";
      s = "lwc2";
 
      fmt = COP12_FMT;
 
      off12 = mips_opts.micromips;
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LWC3_AB:
    case M_LWC3_AB:
 
      ab = 1;
 
      gas_assert (!mips_opts.micromips);
      s = "lwc3";
      s = "lwc3";
 
      fmt = "E,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LWL_AB:
    case M_LWL_AB:
 
      ab = 1;
 
    case M_LWL_OB:
      s = "lwl";
      s = "lwl";
      lr = 1;
      fmt = MEM12_FMT;
      goto ld;
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_LWR_AB:
    case M_LWR_AB:
 
      ab = 1;
 
    case M_LWR_OB:
      s = "lwr";
      s = "lwr";
      lr = 1;
      fmt = MEM12_FMT;
      goto ld;
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_LDC1_AB:
    case M_LDC1_AB:
 
      ab = 1;
      s = "ldc1";
      s = "ldc1";
 
      fmt = "T,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LDC2_AB:
    case M_LDC2_AB:
 
      ab = 1;
 
    case M_LDC2_OB:
      s = "ldc2";
      s = "ldc2";
 
      fmt = COP12_FMT;
 
      off12 = mips_opts.micromips;
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LDC3_AB:
    case M_LDC3_AB:
 
      ab = 1;
      s = "ldc3";
      s = "ldc3";
 
      fmt = "E,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto ld;
      goto ld_st;
    case M_LDL_AB:
    case M_LDL_AB:
 
      ab = 1;
 
    case M_LDL_OB:
      s = "ldl";
      s = "ldl";
      lr = 1;
      fmt = MEM12_FMT;
      goto ld;
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_LDR_AB:
    case M_LDR_AB:
 
      ab = 1;
 
    case M_LDR_OB:
      s = "ldr";
      s = "ldr";
      lr = 1;
      fmt = MEM12_FMT;
      goto ld;
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_LL_AB:
    case M_LL_AB:
 
      ab = 1;
 
    case M_LL_OB:
      s = "ll";
      s = "ll";
 
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
      goto ld;
      goto ld;
    case M_LLD_AB:
    case M_LLD_AB:
 
      ab = 1;
 
    case M_LLD_OB:
      s = "lld";
      s = "lld";
 
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
      goto ld;
      goto ld;
    case M_LWU_AB:
    case M_LWU_AB:
 
      ab = 1;
 
    case M_LWU_OB:
      s = "lwu";
      s = "lwu";
 
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld;
 
    case M_LWP_AB:
 
      ab = 1;
 
    case M_LWP_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "lwp";
 
      fmt = "t,~(b)";
 
      off12 = 1;
 
      lp = 1;
 
      goto ld;
 
    case M_LDP_AB:
 
      ab = 1;
 
    case M_LDP_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "ldp";
 
      fmt = "t,~(b)";
 
      off12 = 1;
 
      lp = 1;
 
      goto ld;
 
    case M_LWM_AB:
 
      ab = 1;
 
    case M_LWM_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "lwm";
 
      fmt = "n,~(b)";
 
      off12 = 1;
 
      goto ld_st;
 
    case M_LDM_AB:
 
      ab = 1;
 
    case M_LDM_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "ldm";
 
      fmt = "n,~(b)";
 
      off12 = 1;
 
      goto ld_st;
 
 
    ld:
    ld:
      if (breg == treg || coproc || lr)
      if (breg == treg + lp)
        {
 
          tempreg = AT;
 
          used_at = 1;
 
        }
 
      else
 
        {
 
          tempreg = treg;
 
        }
 
      goto ld_st;
      goto ld_st;
 
      else
 
        tempreg = treg + lp;
 
      goto ld_noat;
 
 
    case M_SB_AB:
    case M_SB_AB:
 
      ab = 1;
      s = "sb";
      s = "sb";
      goto st;
      fmt = "t,o(b)";
 
      goto ld_st;
    case M_SH_AB:
    case M_SH_AB:
 
      ab = 1;
      s = "sh";
      s = "sh";
      goto st;
      fmt = "t,o(b)";
 
      goto ld_st;
    case M_SW_AB:
    case M_SW_AB:
 
      ab = 1;
      s = "sw";
      s = "sw";
      goto st;
      fmt = "t,o(b)";
 
      goto ld_st;
    case M_SWC0_AB:
    case M_SWC0_AB:
 
      ab = 1;
 
      gas_assert (!mips_opts.micromips);
      s = "swc0";
      s = "swc0";
 
      fmt = "E,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto st;
      goto ld_st;
    case M_SWC1_AB:
    case M_SWC1_AB:
 
      ab = 1;
      s = "swc1";
      s = "swc1";
 
      fmt = "T,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto st;
      goto ld_st;
    case M_SWC2_AB:
    case M_SWC2_AB:
 
      ab = 1;
 
    case M_SWC2_OB:
      s = "swc2";
      s = "swc2";
 
      fmt = COP12_FMT;
 
      off12 = mips_opts.micromips;
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto st;
      goto ld_st;
    case M_SWC3_AB:
    case M_SWC3_AB:
 
      ab = 1;
 
      gas_assert (!mips_opts.micromips);
      s = "swc3";
      s = "swc3";
 
      fmt = "E,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto st;
      goto ld_st;
    case M_SWL_AB:
    case M_SWL_AB:
 
      ab = 1;
 
    case M_SWL_OB:
      s = "swl";
      s = "swl";
      goto st;
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_SWR_AB:
    case M_SWR_AB:
 
      ab = 1;
 
    case M_SWR_OB:
      s = "swr";
      s = "swr";
      goto st;
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_SC_AB:
    case M_SC_AB:
 
      ab = 1;
 
    case M_SC_OB:
      s = "sc";
      s = "sc";
      goto st;
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_SCD_AB:
    case M_SCD_AB:
 
      ab = 1;
 
    case M_SCD_OB:
      s = "scd";
      s = "scd";
      goto st;
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_CACHE_AB:
    case M_CACHE_AB:
 
      ab = 1;
 
    case M_CACHE_OB:
      s = "cache";
      s = "cache";
      goto st;
      fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)";
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_PREF_AB:
    case M_PREF_AB:
 
      ab = 1;
 
    case M_PREF_OB:
      s = "pref";
      s = "pref";
      goto st;
      fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)";
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_SDC1_AB:
    case M_SDC1_AB:
 
      ab = 1;
      s = "sdc1";
      s = "sdc1";
 
      fmt = "T,o(b)";
      coproc = 1;
      coproc = 1;
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      goto st;
      goto ld_st;
    case M_SDC2_AB:
    case M_SDC2_AB:
 
      ab = 1;
 
    case M_SDC2_OB:
      s = "sdc2";
      s = "sdc2";
 
      fmt = COP12_FMT;
 
      off12 = mips_opts.micromips;
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto st;
      goto ld_st;
    case M_SDC3_AB:
    case M_SDC3_AB:
 
      ab = 1;
 
      gas_assert (!mips_opts.micromips);
      s = "sdc3";
      s = "sdc3";
 
      fmt = "E,o(b)";
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
      goto st;
      goto ld_st;
    case M_SDL_AB:
    case M_SDL_AB:
 
      ab = 1;
 
    case M_SDL_OB:
      s = "sdl";
      s = "sdl";
      goto st;
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
    case M_SDR_AB:
    case M_SDR_AB:
 
      ab = 1;
 
    case M_SDR_OB:
      s = "sdr";
      s = "sdr";
    st:
      fmt = MEM12_FMT;
 
      off12 = mips_opts.micromips;
 
      goto ld_st;
 
    case M_SWP_AB:
 
      ab = 1;
 
    case M_SWP_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "swp";
 
      fmt = "t,~(b)";
 
      off12 = 1;
 
      goto ld_st;
 
    case M_SDP_AB:
 
      ab = 1;
 
    case M_SDP_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "sdp";
 
      fmt = "t,~(b)";
 
      off12 = 1;
 
      goto ld_st;
 
    case M_SWM_AB:
 
      ab = 1;
 
    case M_SWM_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "swm";
 
      fmt = "n,~(b)";
 
      off12 = 1;
 
      goto ld_st;
 
    case M_SDM_AB:
 
      ab = 1;
 
    case M_SDM_OB:
 
      gas_assert (mips_opts.micromips);
 
      s = "sdm";
 
      fmt = "n,~(b)";
 
      off12 = 1;
 
 
 
    ld_st:
      tempreg = AT;
      tempreg = AT;
      used_at = 1;
      used_at = 1;
    ld_st:
    ld_noat:
      if (coproc
      if (coproc
          && NO_ISA_COP (mips_opts.arch)
          && NO_ISA_COP (mips_opts.arch)
          && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
          && (ip->insn_mo->pinfo2 & (INSN2_M_FP_S | INSN2_M_FP_D)) == 0)
        {
        {
          as_bad (_("Opcode not supported on this processor: %s"),
          as_bad (_("Opcode not supported on this processor: %s"),
                  mips_cpu_info_from_arch (mips_opts.arch)->name);
                  mips_cpu_info_from_arch (mips_opts.arch)->name);
          break;
          break;
        }
        }
 
 
      /* 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 || mask == M_PREF_AB)
 
        fmt = "k,o(b)";
 
      else if (coproc)
 
        fmt = "E,o(b)";
 
      else
 
        fmt = "t,o(b)";
 
 
 
      if (offset_expr.X_op != O_constant
      if (offset_expr.X_op != O_constant
          && offset_expr.X_op != O_symbol)
          && offset_expr.X_op != O_symbol)
        {
        {
          as_bad (_("Expression too complex"));
          as_bad (_("Expression too complex"));
          offset_expr.X_op = O_constant;
          offset_expr.X_op = O_constant;
Line 6800... Line 8269...
 
 
      /* A constant expression in PIC code can be handled just as it
      /* A constant expression in PIC code can be handled just as it
         is in non PIC code.  */
         is in non PIC code.  */
      if (offset_expr.X_op == O_constant)
      if (offset_expr.X_op == O_constant)
        {
        {
 
          int hipart = 0;
 
 
          expr1.X_add_number = offset_expr.X_add_number;
          expr1.X_add_number = offset_expr.X_add_number;
          normalize_address_expr (&expr1);
          normalize_address_expr (&expr1);
          if (!IS_SEXT_16BIT_NUM (expr1.X_add_number))
          if (!off12 && !IS_SEXT_16BIT_NUM (expr1.X_add_number))
            {
            {
              expr1.X_add_number = ((expr1.X_add_number + 0x8000)
              expr1.X_add_number = ((expr1.X_add_number + 0x8000)
                                    & ~(bfd_vma) 0xffff);
                                    & ~(bfd_vma) 0xffff);
 
              hipart = 1;
 
            }
 
          else if (off12 && !IS_SEXT_12BIT_NUM (expr1.X_add_number))
 
            {
 
              expr1.X_add_number = ((expr1.X_add_number + 0x800)
 
                                    & ~(bfd_vma) 0xfff);
 
              hipart = 1;
 
            }
 
          if (hipart)
 
            {
              load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
              load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
              if (breg != 0)
              if (breg != 0)
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                             tempreg, tempreg, breg);
                             tempreg, tempreg, breg);
              breg = tempreg;
              breg = tempreg;
            }
            }
 
          if (!off12)
          macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
          macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
 
          else
 
            macro_build (NULL, s, fmt,
 
                         treg, (unsigned long) offset_expr.X_add_number, breg);
 
        }
 
      else if (off12)
 
        {
 
          /* A 12-bit offset field is too narrow to be used for a low-part
 
             relocation, so load the whole address into the auxillary
 
             register.  In the case of "A(b)" addresses, we first load
 
             absolute address "A" into the register and then add base
 
             register "b".  In the case of "o(b)" addresses, we simply
 
             need to add 16-bit offset "o" to base register "b", and
 
             offset_reloc already contains the relocations associated
 
             with "o".  */
 
          if (ab)
 
            {
 
              load_address (tempreg, &offset_expr, &used_at);
 
              if (breg != 0)
 
                macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
 
                             tempreg, tempreg, breg);
 
            }
 
          else
 
            macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
 
                         tempreg, breg, -1,
 
                         offset_reloc[0], offset_reloc[1], offset_reloc[2]);
 
          expr1.X_add_number = 0;
 
          macro_build (NULL, s, fmt,
 
                       treg, (unsigned long) expr1.X_add_number, tempreg);
        }
        }
      else if (mips_pic == NO_PIC)
      else if (mips_pic == NO_PIC)
        {
        {
          /* If this is a reference to a GP relative symbol, and there
          /* If this is a reference to a GP relative symbol, and there
             is no base register, we want
             is no base register, we want
Line 6894... Line 8404...
                  relax_switch ();
                  relax_switch ();
                }
                }
 
 
              if (used_at == 0 && mips_opts.at)
              if (used_at == 0 && mips_opts.at)
                {
                {
                  macro_build (&offset_expr, "lui", "t,u", tempreg,
                  macro_build (&offset_expr, "lui", LUI_FMT, tempreg,
                               BFD_RELOC_MIPS_HIGHEST);
                               BFD_RELOC_MIPS_HIGHEST);
                  macro_build (&offset_expr, "lui", "t,u", AT,
                  macro_build (&offset_expr, "lui", LUI_FMT, AT,
                               BFD_RELOC_HI16_S);
                               BFD_RELOC_HI16_S);
                  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                               tempreg, BFD_RELOC_MIPS_HIGHER);
                               tempreg, BFD_RELOC_MIPS_HIGHER);
                  if (breg != 0)
                  if (breg != 0)
                    macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
                    macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
                  macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
                  macro_build (NULL, "dsll32", SHFT_FMT, tempreg, tempreg, 0);
                  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
                  macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
                  macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
                               tempreg);
                               tempreg);
                  used_at = 1;
                  used_at = 1;
                }
                }
              else
              else
                {
                {
                  macro_build (&offset_expr, "lui", "t,u", tempreg,
                  macro_build (&offset_expr, "lui", LUI_FMT, tempreg,
                               BFD_RELOC_MIPS_HIGHEST);
                               BFD_RELOC_MIPS_HIGHEST);
                  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                               tempreg, BFD_RELOC_MIPS_HIGHER);
                               tempreg, BFD_RELOC_MIPS_HIGHER);
                  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                  macro_build (NULL, "dsll", SHFT_FMT, tempreg, tempreg, 16);
                  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
                               tempreg, BFD_RELOC_HI16_S);
                               tempreg, BFD_RELOC_HI16_S);
                  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
                  macro_build (NULL, "dsll", SHFT_FMT, tempreg, tempreg, 16);
                  if (breg != 0)
                  if (breg != 0)
                    macro_build (NULL, "daddu", "d,v,t",
                    macro_build (NULL, "daddu", "d,v,t",
                                 tempreg, tempreg, breg);
                                 tempreg, tempreg, breg);
                  macro_build (&offset_expr, s, fmt, treg,
                  macro_build (&offset_expr, s, fmt, treg,
                               BFD_RELOC_LO16, tempreg);
                               BFD_RELOC_LO16, tempreg);
Line 7049... Line 8559...
          if (expr1.X_add_number < -0x8000
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          gpdelay = reg_needs_delay (mips_gp_register);
          gpdelay = reg_needs_delay (mips_gp_register);
          relax_start (offset_expr.X_add_symbol);
          relax_start (offset_expr.X_add_symbol);
          macro_build (&offset_expr, "lui", "t,u", tempreg,
          macro_build (&offset_expr, "lui", LUI_FMT, tempreg,
                       BFD_RELOC_MIPS_GOT_HI16);
                       BFD_RELOC_MIPS_GOT_HI16);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
                       mips_gp_register);
                       mips_gp_register);
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                       BFD_RELOC_MIPS_GOT_LO16, tempreg);
                       BFD_RELOC_MIPS_GOT_LO16, tempreg);
Line 7087... Line 8597...
          offset_expr.X_add_number = 0;
          offset_expr.X_add_number = 0;
          if (expr1.X_add_number < -0x8000
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000)
              || expr1.X_add_number >= 0x8000)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          relax_start (offset_expr.X_add_symbol);
          relax_start (offset_expr.X_add_symbol);
          macro_build (&offset_expr, "lui", "t,u", tempreg,
          macro_build (&offset_expr, "lui", LUI_FMT, tempreg,
                       BFD_RELOC_MIPS_GOT_HI16);
                       BFD_RELOC_MIPS_GOT_HI16);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
                       mips_gp_register);
                       mips_gp_register);
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
                       BFD_RELOC_MIPS_GOT_LO16, tempreg);
                       BFD_RELOC_MIPS_GOT_LO16, tempreg);
Line 7253... Line 8763...
      gas_assert (offset_expr.X_op == O_symbol
      gas_assert (offset_expr.X_op == O_symbol
                  && offset_expr.X_add_number == 0);
                  && offset_expr.X_add_number == 0);
      s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
      s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
      if (strcmp (s, ".lit8") == 0)
      if (strcmp (s, ".lit8") == 0)
        {
        {
          if (mips_opts.isa != ISA_MIPS1)
          if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips)
            {
            {
              macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
              macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
                           BFD_RELOC_MIPS_LITERAL, mips_gp_register);
                           BFD_RELOC_MIPS_LITERAL, mips_gp_register);
              break;
              break;
            }
            }
Line 7276... Line 8786...
            {
            {
              /* FIXME: This won't work for a 64 bit address.  */
              /* FIXME: This won't work for a 64 bit address.  */
              macro_build_lui (&offset_expr, AT);
              macro_build_lui (&offset_expr, AT);
            }
            }
 
 
          if (mips_opts.isa != ISA_MIPS1)
          if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips)
            {
            {
              macro_build (&offset_expr, "ldc1", "T,o(b)",
              macro_build (&offset_expr, "ldc1", "T,o(b)",
                           treg, BFD_RELOC_LO16, AT);
                           treg, BFD_RELOC_LO16, AT);
              break;
              break;
            }
            }
Line 7292... Line 8802...
    case M_L_DOB:
    case M_L_DOB:
      /* Even on a big endian machine $fn comes before $fn+1.  We have
      /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when loading from memory.  */
         to adjust when loading from memory.  */
      r = BFD_RELOC_LO16;
      r = BFD_RELOC_LO16;
    dob:
    dob:
 
      gas_assert (!mips_opts.micromips);
      gas_assert (mips_opts.isa == ISA_MIPS1);
      gas_assert (mips_opts.isa == ISA_MIPS1);
      macro_build (&offset_expr, "lwc1", "T,o(b)",
      macro_build (&offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg, r, breg);
                   target_big_endian ? treg + 1 : treg, r, breg);
      /* FIXME: A possible overflow which I don't know how to deal
      /* FIXME: A possible overflow which I don't know how to deal
         with.  */
         with.  */
Line 7303... Line 8814...
      macro_build (&offset_expr, "lwc1", "T,o(b)",
      macro_build (&offset_expr, "lwc1", "T,o(b)",
                   target_big_endian ? treg : treg + 1, r, breg);
                   target_big_endian ? treg : treg + 1, r, breg);
      break;
      break;
 
 
    case M_S_DOB:
    case M_S_DOB:
 
      gas_assert (!mips_opts.micromips);
      gas_assert (mips_opts.isa == ISA_MIPS1);
      gas_assert (mips_opts.isa == ISA_MIPS1);
      /* Even on a big endian machine $fn comes before $fn+1.  We have
      /* Even on a big endian machine $fn comes before $fn+1.  We have
         to adjust when storing to memory.  */
         to adjust when storing to memory.  */
      macro_build (&offset_expr, "swc1", "T,o(b)",
      macro_build (&offset_expr, "swc1", "T,o(b)",
                   target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
                   target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
Line 7314... Line 8826...
      macro_build (&offset_expr, "swc1", "T,o(b)",
      macro_build (&offset_expr, "swc1", "T,o(b)",
                   target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
                   target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
      break;
      break;
 
 
    case M_L_DAB:
    case M_L_DAB:
 
      gas_assert (!mips_opts.micromips);
      /*
      /*
       * The MIPS assembler seems to check for X_add_number not
       * The MIPS assembler seems to check for X_add_number not
       * being double aligned and generating:
       * being double aligned and generating:
       *        lui     at,%hi(foo+1)
       *        lui     at,%hi(foo+1)
       *        addu    at,at,v1
       *        addu    at,at,v1
Line 7327... Line 8840...
       * But, the resulting address is the same after relocation so why
       * But, the resulting address is the same after relocation so why
       * generate the extra instruction?
       * generate the extra instruction?
       */
       */
      /* Itbl support may require additional care here.  */
      /* Itbl support may require additional care here.  */
      coproc = 1;
      coproc = 1;
 
      fmt = "T,o(b)";
      if (mips_opts.isa != ISA_MIPS1)
      if (mips_opts.isa != ISA_MIPS1)
        {
        {
          s = "ldc1";
          s = "ldc1";
          goto ld;
          goto ld_st;
        }
        }
 
 
      s = "lwc1";
      s = "lwc1";
      fmt = "T,o(b)";
 
      goto ldd_std;
      goto ldd_std;
 
 
    case M_S_DAB:
    case M_S_DAB:
 
      gas_assert (!mips_opts.micromips);
 
      /* Itbl support may require additional care here.  */
 
      coproc = 1;
 
      fmt = "T,o(b)";
      if (mips_opts.isa != ISA_MIPS1)
      if (mips_opts.isa != ISA_MIPS1)
        {
        {
          s = "sdc1";
          s = "sdc1";
          goto st;
          goto ld_st;
        }
        }
 
 
      s = "swc1";
      s = "swc1";
      fmt = "T,o(b)";
 
      /* Itbl support may require additional care here.  */
 
      coproc = 1;
 
      goto ldd_std;
      goto ldd_std;
 
 
    case M_LD_AB:
    case M_LD_AB:
 
      fmt = "t,o(b)";
      if (HAVE_64BIT_GPRS)
      if (HAVE_64BIT_GPRS)
        {
        {
          s = "ld";
          s = "ld";
          goto ld;
          goto ld;
        }
        }
 
 
      s = "lw";
      s = "lw";
      fmt = "t,o(b)";
 
      goto ldd_std;
      goto ldd_std;
 
 
    case M_SD_AB:
    case M_SD_AB:
 
      fmt = "t,o(b)";
      if (HAVE_64BIT_GPRS)
      if (HAVE_64BIT_GPRS)
        {
        {
          s = "sd";
          s = "sd";
          goto st;
          goto ld_st;
        }
        }
 
 
      s = "sw";
      s = "sw";
      fmt = "t,o(b)";
 
 
 
    ldd_std:
    ldd_std:
      if (offset_expr.X_op != O_symbol
      if (offset_expr.X_op != O_symbol
          && offset_expr.X_op != O_constant)
          && offset_expr.X_op != O_constant)
        {
        {
Line 7535... Line 9045...
          if (expr1.X_add_number < -0x8000
          if (expr1.X_add_number < -0x8000
              || expr1.X_add_number >= 0x8000 - 4)
              || expr1.X_add_number >= 0x8000 - 4)
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
            as_bad (_("PIC code offset overflow (max 16 signed bits)"));
          gpdelay = reg_needs_delay (mips_gp_register);
          gpdelay = reg_needs_delay (mips_gp_register);
          relax_start (offset_expr.X_add_symbol);
          relax_start (offset_expr.X_add_symbol);
          macro_build (&offset_expr, "lui", "t,u",
          macro_build (&offset_expr, "lui", LUI_FMT,
                       AT, BFD_RELOC_MIPS_GOT_HI16);
                       AT, BFD_RELOC_MIPS_GOT_HI16);
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
          macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
                       AT, AT, mips_gp_register);
                       AT, AT, mips_gp_register);
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
          macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
                       AT, BFD_RELOC_MIPS_GOT_LO16, AT);
                       AT, BFD_RELOC_MIPS_GOT_LO16, AT);
Line 7635... Line 9145...
      s = "c2";
      s = "c2";
      goto copz;
      goto copz;
    case M_COP3:
    case M_COP3:
      s = "c3";
      s = "c3";
    copz:
    copz:
 
      gas_assert (!mips_opts.micromips);
      if (NO_ISA_COP (mips_opts.arch)
      if (NO_ISA_COP (mips_opts.arch)
          && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
          && (ip->insn_mo->pinfo2 & INSN2_M_FP_S) == 0)
        {
        {
          as_bad (_("opcode not supported on this processor: %s"),
          as_bad (_("opcode not supported on this processor: %s"),
                  mips_cpu_info_from_arch (mips_opts.arch)->name);
                  mips_cpu_info_from_arch (mips_opts.arch)->name);
Line 7656... Line 9167...
 
 
    case M_DMUL:
    case M_DMUL:
      dbl = 1;
      dbl = 1;
    case M_MUL:
    case M_MUL:
      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
      macro_build (NULL, "mflo", "d", dreg);
      macro_build (NULL, "mflo", MFHL_FMT, dreg);
      break;
      break;
 
 
    case M_DMUL_I:
    case M_DMUL_I:
      dbl = 1;
      dbl = 1;
    case M_MUL_I:
    case M_MUL_I:
Line 7668... Line 9179...
         not trying to be that fancy. GCC should do this for us
         not trying to be that fancy. GCC should do this for us
         anyway.  */
         anyway.  */
      used_at = 1;
      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
      macro_build (NULL, "mflo", "d", dreg);
      macro_build (NULL, "mflo", MFHL_FMT, dreg);
      break;
      break;
 
 
    case M_DMULO_I:
    case M_DMULO_I:
      dbl = 1;
      dbl = 1;
    case M_MULO_I:
    case M_MULO_I:
Line 7686... Line 9197...
      start_noreorder ();
      start_noreorder ();
      used_at = 1;
      used_at = 1;
      if (imm)
      if (imm)
        load_register (AT, &imm_expr, dbl);
        load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
      macro_build (NULL, "mflo", "d", dreg);
      macro_build (NULL, "mflo", MFHL_FMT, dreg);
      macro_build (NULL, dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, RA);
      macro_build (NULL, dbl ? "dsra32" : "sra", SHFT_FMT, dreg, dreg, RA);
      macro_build (NULL, "mfhi", "d", AT);
      macro_build (NULL, "mfhi", MFHL_FMT, AT);
      if (mips_trap)
      if (mips_trap)
        macro_build (NULL, "tne", "s,t,q", dreg, AT, 6);
        macro_build (NULL, "tne", TRAP_FMT, dreg, AT, 6);
      else
      else
        {
        {
          expr1.X_add_number = 8;
          if (mips_opts.micromips)
          macro_build (&expr1, "beq", "s,t,p", dreg, AT);
            micromips_label_expr (&label_expr);
 
          else
 
            label_expr.X_add_number = 8;
 
          macro_build (&label_expr, "beq", "s,t,p", dreg, AT);
          macro_build (NULL, "nop", "");
          macro_build (NULL, "nop", "");
          macro_build (NULL, "break", "c", 6);
          macro_build (NULL, "break", BRK_FMT, 6);
 
          if (mips_opts.micromips)
 
            micromips_add_label ();
        }
        }
      end_noreorder ();
      end_noreorder ();
      macro_build (NULL, "mflo", "d", dreg);
      macro_build (NULL, "mflo", MFHL_FMT, dreg);
      break;
      break;
 
 
    case M_DMULOU_I:
    case M_DMULOU_I:
      dbl = 1;
      dbl = 1;
    case M_MULOU_I:
    case M_MULOU_I:
Line 7718... Line 9234...
      used_at = 1;
      used_at = 1;
      if (imm)
      if (imm)
        load_register (AT, &imm_expr, dbl);
        load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
                   sreg, imm ? AT : treg);
                   sreg, imm ? AT : treg);
      macro_build (NULL, "mfhi", "d", AT);
      macro_build (NULL, "mfhi", MFHL_FMT, AT);
      macro_build (NULL, "mflo", "d", dreg);
      macro_build (NULL, "mflo", MFHL_FMT, dreg);
      if (mips_trap)
      if (mips_trap)
        macro_build (NULL, "tne", "s,t,q", AT, ZERO, 6);
        macro_build (NULL, "tne", TRAP_FMT, AT, ZERO, 6);
      else
      else
        {
        {
          expr1.X_add_number = 8;
          if (mips_opts.micromips)
          macro_build (&expr1, "beq", "s,t,p", AT, ZERO);
            micromips_label_expr (&label_expr);
 
          else
 
            label_expr.X_add_number = 8;
 
          macro_build (&label_expr, "beq", "s,t,p", AT, ZERO);
          macro_build (NULL, "nop", "");
          macro_build (NULL, "nop", "");
          macro_build (NULL, "break", "c", 6);
          macro_build (NULL, "break", BRK_FMT, 6);
 
          if (mips_opts.micromips)
 
            micromips_add_label ();
        }
        }
      end_noreorder ();
      end_noreorder ();
      break;
      break;
 
 
    case M_DROL:
    case M_DROL:
Line 7791... Line 9312...
        rot = imm_expr.X_add_number & 0x3f;
        rot = imm_expr.X_add_number & 0x3f;
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
          {
          {
            rot = (64 - rot) & 0x3f;
            rot = (64 - rot) & 0x3f;
            if (rot >= 32)
            if (rot >= 32)
              macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
              macro_build (NULL, "dror32", SHFT_FMT, dreg, sreg, rot - 32);
            else
            else
              macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
              macro_build (NULL, "dror", SHFT_FMT, dreg, sreg, rot);
            break;
            break;
          }
          }
        if (rot == 0)
        if (rot == 0)
          {
          {
            macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
            macro_build (NULL, "dsrl", SHFT_FMT, dreg, sreg, 0);
            break;
            break;
          }
          }
        l = (rot < 0x20) ? "dsll" : "dsll32";
        l = (rot < 0x20) ? "dsll" : "dsll32";
        rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rr = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
        rot &= 0x1f;
        rot &= 0x1f;
        used_at = 1;
        used_at = 1;
        macro_build (NULL, l, "d,w,<", AT, sreg, rot);
        macro_build (NULL, l, SHFT_FMT, AT, sreg, rot);
        macro_build (NULL, rr, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, rr, SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      }
      break;
      break;
 
 
    case M_ROL_I:
    case M_ROL_I:
Line 7820... Line 9341...
        if (imm_expr.X_op != O_constant)
        if (imm_expr.X_op != O_constant)
          as_bad (_("Improper rotate count"));
          as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x1f;
        rot = imm_expr.X_add_number & 0x1f;
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
          {
          {
            macro_build (NULL, "ror", "d,w,<", dreg, sreg, (32 - rot) & 0x1f);
            macro_build (NULL, "ror", SHFT_FMT, dreg, sreg, (32 - rot) & 0x1f);
            break;
            break;
          }
          }
        if (rot == 0)
        if (rot == 0)
          {
          {
            macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
            macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, 0);
            break;
            break;
          }
          }
        used_at = 1;
        used_at = 1;
        macro_build (NULL, "sll", "d,w,<", AT, sreg, rot);
        macro_build (NULL, "sll", SHFT_FMT, AT, sreg, rot);
        macro_build (NULL, "srl", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      }
      break;
      break;
 
 
    case M_DROR:
    case M_DROR:
Line 7873... Line 9394...
          as_bad (_("Improper rotate count"));
          as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x3f;
        rot = imm_expr.X_add_number & 0x3f;
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
        if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
          {
          {
            if (rot >= 32)
            if (rot >= 32)
              macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
              macro_build (NULL, "dror32", SHFT_FMT, dreg, sreg, rot - 32);
            else
            else
              macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
              macro_build (NULL, "dror", SHFT_FMT, dreg, sreg, rot);
            break;
            break;
          }
          }
        if (rot == 0)
        if (rot == 0)
          {
          {
            macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
            macro_build (NULL, "dsrl", SHFT_FMT, dreg, sreg, 0);
            break;
            break;
          }
          }
        rr = (rot < 0x20) ? "dsrl" : "dsrl32";
        rr = (rot < 0x20) ? "dsrl" : "dsrl32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
        rot &= 0x1f;
        rot &= 0x1f;
        used_at = 1;
        used_at = 1;
        macro_build (NULL, rr, "d,w,<", AT, sreg, rot);
        macro_build (NULL, rr, SHFT_FMT, AT, sreg, rot);
        macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, l, SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      }
      break;
      break;
 
 
    case M_ROR_I:
    case M_ROR_I:
Line 7902... Line 9423...
        if (imm_expr.X_op != O_constant)
        if (imm_expr.X_op != O_constant)
          as_bad (_("Improper rotate count"));
          as_bad (_("Improper rotate count"));
        rot = imm_expr.X_add_number & 0x1f;
        rot = imm_expr.X_add_number & 0x1f;
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
        if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
          {
          {
            macro_build (NULL, "ror", "d,w,<", dreg, sreg, rot);
            macro_build (NULL, "ror", SHFT_FMT, dreg, sreg, rot);
            break;
            break;
          }
          }
        if (rot == 0)
        if (rot == 0)
          {
          {
            macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
            macro_build (NULL, "srl", SHFT_FMT, dreg, sreg, 0);
            break;
            break;
          }
          }
        used_at = 1;
        used_at = 1;
        macro_build (NULL, "srl", "d,w,<", AT, sreg, rot);
        macro_build (NULL, "srl", SHFT_FMT, AT, sreg, rot);
        macro_build (NULL, "sll", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "sll", SHFT_FMT, dreg, sreg, (0x20 - rot) & 0x1f);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
        macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
      }
      }
      break;
      break;
 
 
    case M_SEQ:
    case M_SEQ:
Line 8142... Line 9663...
          used_at = 1;
          used_at = 1;
        }
        }
      macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
      macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
      break;
      break;
 
 
 
    case M_SUB_I:
 
      s = "addi";
 
      s2 = "sub";
 
      goto do_subi;
 
    case M_SUBU_I:
 
      s = "addiu";
 
      s2 = "subu";
 
      goto do_subi;
    case M_DSUB_I:
    case M_DSUB_I:
      dbl = 1;
      dbl = 1;
    case M_SUB_I:
      s = "daddi";
 
      s2 = "dsub";
 
      if (!mips_opts.micromips)
 
        goto do_subi;
      if (imm_expr.X_op == O_constant
      if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number > -0x8000
          && imm_expr.X_add_number > -0x200
          && imm_expr.X_add_number <= 0x8000)
          && imm_expr.X_add_number <= 0x200)
        {
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build (NULL, s, "t,r,.", dreg, sreg, -imm_expr.X_add_number);
          macro_build (&imm_expr, dbl ? "daddi" : "addi", "t,r,j",
 
                       dreg, sreg, BFD_RELOC_LO16);
 
          break;
          break;
        }
        }
      used_at = 1;
      goto do_subi_i;
      load_register (AT, &imm_expr, dbl);
 
      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, sreg, AT);
 
      break;
 
 
 
    case M_DSUBU_I:
    case M_DSUBU_I:
      dbl = 1;
      dbl = 1;
    case M_SUBU_I:
      s = "daddiu";
 
      s2 = "dsubu";
 
    do_subi:
      if (imm_expr.X_op == O_constant
      if (imm_expr.X_op == O_constant
          && imm_expr.X_add_number > -0x8000
          && imm_expr.X_add_number > -0x8000
          && imm_expr.X_add_number <= 0x8000)
          && imm_expr.X_add_number <= 0x8000)
        {
        {
          imm_expr.X_add_number = -imm_expr.X_add_number;
          imm_expr.X_add_number = -imm_expr.X_add_number;
          macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "t,r,j",
          macro_build (&imm_expr, s, "t,r,j", dreg, sreg, BFD_RELOC_LO16);
                       dreg, sreg, BFD_RELOC_LO16);
 
          break;
          break;
        }
        }
 
    do_subi_i:
      used_at = 1;
      used_at = 1;
      load_register (AT, &imm_expr, dbl);
      load_register (AT, &imm_expr, dbl);
      macro_build (NULL, dbl ? "dsubu" : "subu", "d,v,t", dreg, sreg, AT);
      macro_build (NULL, s2, "d,v,t", dreg, sreg, AT);
      break;
      break;
 
 
    case M_TEQ_I:
    case M_TEQ_I:
      s = "teq";
      s = "teq";
      goto trap;
      goto trap;
Line 8201... Line 9729...
      macro_build (NULL, s, "s,t", sreg, AT);
      macro_build (NULL, s, "s,t", sreg, AT);
      break;
      break;
 
 
    case M_TRUNCWS:
    case M_TRUNCWS:
    case M_TRUNCWD:
    case M_TRUNCWD:
 
      gas_assert (!mips_opts.micromips);
      gas_assert (mips_opts.isa == ISA_MIPS1);
      gas_assert (mips_opts.isa == ISA_MIPS1);
      used_at = 1;
      used_at = 1;
      sreg = (ip->insn_opcode >> 11) & 0x1f;    /* floating reg */
      sreg = (ip->insn_opcode >> 11) & 0x1f;    /* floating reg */
      dreg = (ip->insn_opcode >> 06) & 0x1f;    /* floating reg */
      dreg = (ip->insn_opcode >> 06) & 0x1f;    /* floating reg */
 
 
Line 8227... Line 9756...
      macro_build (NULL, "ctc1", "t,G", treg, RA);
      macro_build (NULL, "ctc1", "t,G", treg, RA);
      macro_build (NULL, "nop", "");
      macro_build (NULL, "nop", "");
      end_noreorder ();
      end_noreorder ();
      break;
      break;
 
 
 
    case M_ULH_A:
 
      ab = 1;
    case M_ULH:
    case M_ULH:
      s = "lb";
      s = "lb";
      goto ulh;
      s2 = "lbu";
 
      off = 1;
 
      goto uld_st;
 
    case M_ULHU_A:
 
      ab = 1;
    case M_ULHU:
    case M_ULHU:
      s = "lbu";
      s = "lbu";
    ulh:
      s2 = "lbu";
      used_at = 1;
      off = 1;
      if (offset_expr.X_add_number >= 0x7fff)
      goto uld_st;
        as_bad (_("Operand overflow"));
    case M_ULW_A:
      if (!target_big_endian)
      ab = 1;
        ++offset_expr.X_add_number;
    case M_ULW:
      macro_build (&offset_expr, s, "t,o(b)", AT, BFD_RELOC_LO16, breg);
      s = "lwl";
      if (!target_big_endian)
      s2 = "lwr";
        --offset_expr.X_add_number;
      off12 = mips_opts.micromips;
      else
      off = 3;
        ++offset_expr.X_add_number;
      goto uld_st;
      macro_build (&offset_expr, "lbu", "t,o(b)", treg, BFD_RELOC_LO16, breg);
    case M_ULD_A:
      macro_build (NULL, "sll", "d,w,<", AT, AT, 8);
      ab = 1;
      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
 
      break;
 
 
 
    case M_ULD:
    case M_ULD:
      s = "ldl";
      s = "ldl";
      s2 = "ldr";
      s2 = "ldr";
 
      off12 = mips_opts.micromips;
      off = 7;
      off = 7;
      goto ulw;
      goto uld_st;
    case M_ULW:
    case M_USH_A:
      s = "lwl";
      ab = 1;
      s2 = "lwr";
    case M_USH:
 
      s = "sb";
 
      s2 = "sb";
 
      off = 1;
 
      ust = 1;
 
      goto uld_st;
 
    case M_USW_A:
 
      ab = 1;
 
    case M_USW:
 
      s = "swl";
 
      s2 = "swr";
 
      off12 = mips_opts.micromips;
      off = 3;
      off = 3;
    ulw:
      ust = 1;
      if (offset_expr.X_add_number >= 0x8000 - off)
      goto uld_st;
 
    case M_USD_A:
 
      ab = 1;
 
    case M_USD:
 
      s = "sdl";
 
      s2 = "sdr";
 
      off12 = mips_opts.micromips;
 
      off = 7;
 
      ust = 1;
 
 
 
    uld_st:
 
      if (!ab && offset_expr.X_add_number >= 0x8000 - off)
        as_bad (_("Operand overflow"));
        as_bad (_("Operand overflow"));
      if (treg != breg)
 
 
      ep = &offset_expr;
 
      expr1.X_add_number = 0;
 
      if (ab)
 
        {
 
          used_at = 1;
 
          tempreg = AT;
 
          load_address (tempreg, ep, &used_at);
 
          if (breg != 0)
 
            macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
 
                         tempreg, tempreg, breg);
 
          breg = tempreg;
        tempreg = treg;
        tempreg = treg;
      else
          ep = &expr1;
 
        }
 
      else if (off12
 
               && (offset_expr.X_op != O_constant
 
                   || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number)
 
                   || !IS_SEXT_12BIT_NUM (offset_expr.X_add_number + off)))
 
        {
 
          used_at = 1;
 
          tempreg = AT;
 
          macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg,
 
                       -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
 
          breg = tempreg;
 
          tempreg = treg;
 
          ep = &expr1;
 
        }
 
      else if (!ust && treg == breg)
        {
        {
          used_at = 1;
          used_at = 1;
          tempreg = AT;
          tempreg = AT;
        }
        }
 
      else
 
        tempreg = treg;
 
 
 
      if (off == 1)
 
        goto ulh_sh;
 
 
      if (!target_big_endian)
      if (!target_big_endian)
        offset_expr.X_add_number += off;
        ep->X_add_number += off;
      macro_build (&offset_expr, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
      if (!off12)
 
        macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
 
      else
 
        macro_build (NULL, s, "t,~(b)",
 
                     tempreg, (unsigned long) ep->X_add_number, breg);
 
 
      if (!target_big_endian)
      if (!target_big_endian)
        offset_expr.X_add_number -= off;
        ep->X_add_number -= off;
      else
      else
        offset_expr.X_add_number += off;
        ep->X_add_number += off;
      macro_build (&offset_expr, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
      if (!off12)
 
        macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
 
      else
 
        macro_build (NULL, s2, "t,~(b)",
 
                     tempreg, (unsigned long) ep->X_add_number, breg);
 
 
      /* If necessary, move the result in tempreg to the final destination.  */
      /* If necessary, move the result in tempreg to the final destination.  */
      if (treg == tempreg)
      if (!ust && treg != tempreg)
        break;
        {
      /* Protect second load's delay slot.  */
      /* Protect second load's delay slot.  */
      load_delay_nop ();
      load_delay_nop ();
      move_register (treg, tempreg);
      move_register (treg, tempreg);
 
        }
      break;
      break;
 
 
    case M_ULD_A:
    ulh_sh:
      s = "ldl";
 
      s2 = "ldr";
 
      off = 7;
 
      goto ulwa;
 
    case M_ULW_A:
 
      s = "lwl";
 
      s2 = "lwr";
 
      off = 3;
 
    ulwa:
 
      used_at = 1;
      used_at = 1;
      load_address (AT, &offset_expr, &used_at);
      if (target_big_endian == ust)
      if (breg != 0)
        ep->X_add_number += off;
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
      tempreg = ust || ab ? treg : AT;
      if (!target_big_endian)
      macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
        expr1.X_add_number = off;
 
      else
      /* For halfword transfers we need a temporary register to shuffle
        expr1.X_add_number = 0;
         bytes.  Unfortunately for M_USH_A we have none available before
      macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
         the next store as AT holds the base address.  We deal with this
      if (!target_big_endian)
         case by clobbering TREG and then restoring it as with ULH.  */
        expr1.X_add_number = 0;
      tempreg = ust == ab ? treg : AT;
 
      if (ust)
 
        macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8);
 
 
 
      if (target_big_endian == ust)
 
        ep->X_add_number -= off;
      else
      else
        expr1.X_add_number = off;
        ep->X_add_number += off;
      macro_build (&expr1, s2, "t,o(b)", treg, BFD_RELOC_LO16, AT);
      macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
      break;
 
 
 
    case M_ULH_A:
 
    case M_ULHU_A:
 
      used_at = 1;
 
      load_address (AT, &offset_expr, &used_at);
 
      if (breg != 0)
 
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
 
      if (target_big_endian)
 
        expr1.X_add_number = 0;
 
      macro_build (&expr1, mask == M_ULH_A ? "lb" : "lbu", "t,o(b)",
 
                   treg, BFD_RELOC_LO16, AT);
 
      if (target_big_endian)
 
        expr1.X_add_number = 1;
 
      else
 
        expr1.X_add_number = 0;
 
      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
 
      macro_build (NULL, "sll", "d,w,<", treg, treg, 8);
 
      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
 
      break;
 
 
 
    case M_USH:
      /* For M_USH_A re-retrieve the LSB.  */
      used_at = 1;
      if (ust && ab)
      if (offset_expr.X_add_number >= 0x7fff)
        {
        as_bad (_("Operand overflow"));
 
      if (target_big_endian)
 
        ++offset_expr.X_add_number;
 
      macro_build (&offset_expr, "sb", "t,o(b)", treg, BFD_RELOC_LO16, breg);
 
      macro_build (NULL, "srl", "d,w,<", AT, treg, 8);
 
      if (target_big_endian)
      if (target_big_endian)
        --offset_expr.X_add_number;
            ep->X_add_number += off;
      else
 
        ++offset_expr.X_add_number;
 
      macro_build (&offset_expr, "sb", "t,o(b)", AT, BFD_RELOC_LO16, breg);
 
      break;
 
 
 
    case M_USD:
 
      s = "sdl";
 
      s2 = "sdr";
 
      off = 7;
 
      goto usw;
 
    case M_USW:
 
      s = "swl";
 
      s2 = "swr";
 
      off = 3;
 
    usw:
 
      if (offset_expr.X_add_number >= 0x8000 - off)
 
        as_bad (_("Operand overflow"));
 
      if (!target_big_endian)
 
        offset_expr.X_add_number += off;
 
      macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
 
      if (!target_big_endian)
 
        offset_expr.X_add_number -= off;
 
      else
 
        offset_expr.X_add_number += off;
 
      macro_build (&offset_expr, s2, "t,o(b)", treg, BFD_RELOC_LO16, breg);
 
      break;
 
 
 
    case M_USD_A:
 
      s = "sdl";
 
      s2 = "sdr";
 
      off = 7;
 
      goto uswa;
 
    case M_USW_A:
 
      s = "swl";
 
      s2 = "swr";
 
      off = 3;
 
    uswa:
 
      used_at = 1;
 
      load_address (AT, &offset_expr, &used_at);
 
      if (breg != 0)
 
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
 
      if (!target_big_endian)
 
        expr1.X_add_number = off;
 
      else
 
        expr1.X_add_number = 0;
 
      macro_build (&expr1, s, "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
      if (!target_big_endian)
 
        expr1.X_add_number = 0;
 
      else
 
        expr1.X_add_number = off;
 
      macro_build (&expr1, s2, "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
      break;
 
 
 
    case M_USH_A:
 
      used_at = 1;
 
      load_address (AT, &offset_expr, &used_at);
 
      if (breg != 0)
 
        macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
 
      if (!target_big_endian)
 
        expr1.X_add_number = 0;
 
      macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
      macro_build (NULL, "srl", "d,w,<", treg, treg, 8);
 
      if (!target_big_endian)
 
        expr1.X_add_number = 1;
 
      else
 
        expr1.X_add_number = 0;
 
      macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
 
      if (!target_big_endian)
 
        expr1.X_add_number = 0;
 
      else
      else
        expr1.X_add_number = 1;
            ep->X_add_number -= off;
      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
      macro_build (NULL, "sll", "d,w,<", treg, treg, 8);
        }
 
      /* For ULH and M_USH_A OR the LSB in.  */
 
      if (!ust || ab)
 
        {
 
          tempreg = !ab ? AT : treg;
 
          macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8);
      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
 
        }
      break;
      break;
 
 
    default:
    default:
      /* FIXME: Check if this is one of the itbl macros, since they
      /* FIXME: Check if this is one of the itbl macros, since they
         are added dynamically.  */
         are added dynamically.  */
Line 8790... Line 10295...
      case '@': USE_BITS (OP_MASK_IMM10,        OP_SH_IMM10);   break;
      case '@': USE_BITS (OP_MASK_IMM10,        OP_SH_IMM10);   break;
      case '!': USE_BITS (OP_MASK_MT_U,         OP_SH_MT_U);    break;
      case '!': USE_BITS (OP_MASK_MT_U,         OP_SH_MT_U);    break;
      case '$': USE_BITS (OP_MASK_MT_H,         OP_SH_MT_H);    break;
      case '$': USE_BITS (OP_MASK_MT_H,         OP_SH_MT_H);    break;
      case '*': USE_BITS (OP_MASK_MTACC_T,      OP_SH_MTACC_T); break;
      case '*': USE_BITS (OP_MASK_MTACC_T,      OP_SH_MTACC_T); break;
      case '&': USE_BITS (OP_MASK_MTACC_D,      OP_SH_MTACC_D); break;
      case '&': USE_BITS (OP_MASK_MTACC_D,      OP_SH_MTACC_D); break;
 
      case '\\': USE_BITS (OP_MASK_3BITPOS,     OP_SH_3BITPOS); break;
 
      case '~': USE_BITS (OP_MASK_OFFSET12,     OP_SH_OFFSET12); break;
      case 'g': USE_BITS (OP_MASK_RD,           OP_SH_RD);      break;
      case 'g': USE_BITS (OP_MASK_RD,           OP_SH_RD);      break;
      default:
      default:
        as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
        as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
                c, opc->name, opc->args);
                c, opc->name, opc->args);
        return 0;
        return 0;
Line 8806... Line 10313...
      return 0;
      return 0;
    }
    }
  return 1;
  return 1;
}
}
 
 
 
/* For consistency checking, verify that the length implied matches the
 
   major opcode and that all bits are specified either by the match/mask
 
   part of the instruction definition, or by the operand list.  */
 
 
 
static int
 
validate_micromips_insn (const struct mips_opcode *opc)
 
{
 
  unsigned long match = opc->match;
 
  unsigned long mask = opc->mask;
 
  const char *p = opc->args;
 
  unsigned long insn_bits;
 
  unsigned long used_bits;
 
  unsigned long major;
 
  unsigned int length;
 
  char e;
 
  char c;
 
 
 
  if ((mask & match) != match)
 
    {
 
      as_bad (_("Internal error: bad microMIPS opcode (mask error): %s %s"),
 
              opc->name, opc->args);
 
      return 0;
 
    }
 
  length = micromips_insn_length (opc);
 
  if (length != 2 && length != 4)
 
    {
 
      as_bad (_("Internal error: bad microMIPS opcode (incorrect length: %u): "
 
                "%s %s"), length, opc->name, opc->args);
 
      return 0;
 
    }
 
  major = match >> (10 + 8 * (length - 2));
 
  if ((length == 2 && (major & 7) != 1 && (major & 6) != 2)
 
      || (length == 4 && (major & 7) != 0 && (major & 4) != 4))
 
    {
 
      as_bad (_("Internal error: bad microMIPS opcode "
 
                "(opcode/length mismatch): %s %s"), opc->name, opc->args);
 
      return 0;
 
    }
 
 
 
  /* Shift piecewise to avoid an overflow where unsigned long is 32-bit.  */
 
  insn_bits = 1 << 4 * length;
 
  insn_bits <<= 4 * length;
 
  insn_bits -= 1;
 
  used_bits = mask;
 
#define USE_BITS(field) \
 
  (used_bits |= MICROMIPSOP_MASK_##field << MICROMIPSOP_SH_##field)
 
  while (*p)
 
    switch (c = *p++)
 
      {
 
      case ',': break;
 
      case '(': break;
 
      case ')': break;
 
      case '+':
 
        e = c;
 
        switch (c = *p++)
 
          {
 
          case 'A': USE_BITS (EXTLSB);  break;
 
          case 'B': USE_BITS (INSMSB);  break;
 
          case 'C': USE_BITS (EXTMSBD); break;
 
          case 'D': USE_BITS (RS);      USE_BITS (SEL); break;
 
          case 'E': USE_BITS (EXTLSB);  break;
 
          case 'F': USE_BITS (INSMSB);  break;
 
          case 'G': USE_BITS (EXTMSBD); break;
 
          case 'H': USE_BITS (EXTMSBD); break;
 
          default:
 
            as_bad (_("Internal error: bad mips opcode "
 
                      "(unknown extension operand type `%c%c'): %s %s"),
 
                    e, c, opc->name, opc->args);
 
            return 0;
 
          }
 
        break;
 
      case 'm':
 
        e = c;
 
        switch (c = *p++)
 
          {
 
          case 'A': USE_BITS (IMMA);    break;
 
          case 'B': USE_BITS (IMMB);    break;
 
          case 'C': USE_BITS (IMMC);    break;
 
          case 'D': USE_BITS (IMMD);    break;
 
          case 'E': USE_BITS (IMME);    break;
 
          case 'F': USE_BITS (IMMF);    break;
 
          case 'G': USE_BITS (IMMG);    break;
 
          case 'H': USE_BITS (IMMH);    break;
 
          case 'I': USE_BITS (IMMI);    break;
 
          case 'J': USE_BITS (IMMJ);    break;
 
          case 'L': USE_BITS (IMML);    break;
 
          case 'M': USE_BITS (IMMM);    break;
 
          case 'N': USE_BITS (IMMN);    break;
 
          case 'O': USE_BITS (IMMO);    break;
 
          case 'P': USE_BITS (IMMP);    break;
 
          case 'Q': USE_BITS (IMMQ);    break;
 
          case 'U': USE_BITS (IMMU);    break;
 
          case 'W': USE_BITS (IMMW);    break;
 
          case 'X': USE_BITS (IMMX);    break;
 
          case 'Y': USE_BITS (IMMY);    break;
 
          case 'Z': break;
 
          case 'a': break;
 
          case 'b': USE_BITS (MB);      break;
 
          case 'c': USE_BITS (MC);      break;
 
          case 'd': USE_BITS (MD);      break;
 
          case 'e': USE_BITS (ME);      break;
 
          case 'f': USE_BITS (MF);      break;
 
          case 'g': USE_BITS (MG);      break;
 
          case 'h': USE_BITS (MH);      break;
 
          case 'i': USE_BITS (MI);      break;
 
          case 'j': USE_BITS (MJ);      break;
 
          case 'l': USE_BITS (ML);      break;
 
          case 'm': USE_BITS (MM);      break;
 
          case 'n': USE_BITS (MN);      break;
 
          case 'p': USE_BITS (MP);      break;
 
          case 'q': USE_BITS (MQ);      break;
 
          case 'r': break;
 
          case 's': break;
 
          case 't': break;
 
          case 'x': break;
 
          case 'y': break;
 
          case 'z': break;
 
          default:
 
            as_bad (_("Internal error: bad mips opcode "
 
                      "(unknown extension operand type `%c%c'): %s %s"),
 
                    e, c, opc->name, opc->args);
 
            return 0;
 
          }
 
        break;
 
      case '.': USE_BITS (OFFSET10);    break;
 
      case '1': USE_BITS (STYPE);       break;
 
      case '<': USE_BITS (SHAMT);       break;
 
      case '>': USE_BITS (SHAMT);       break;
 
      case 'B': USE_BITS (CODE10);      break;
 
      case 'C': USE_BITS (COPZ);        break;
 
      case 'D': USE_BITS (FD);          break;
 
      case 'E': USE_BITS (RT);          break;
 
      case 'G': USE_BITS (RS);          break;
 
      case 'H': USE_BITS (SEL); break;
 
      case 'K': USE_BITS (RS);          break;
 
      case 'M': USE_BITS (CCC);         break;
 
      case 'N': USE_BITS (BCC);         break;
 
      case 'R': USE_BITS (FR);          break;
 
      case 'S': USE_BITS (FS);          break;
 
      case 'T': USE_BITS (FT);          break;
 
      case 'V': USE_BITS (FS);          break;
 
      case '\\': USE_BITS (3BITPOS);    break;
 
      case 'a': USE_BITS (TARGET);      break;
 
      case 'b': USE_BITS (RS);          break;
 
      case 'c': USE_BITS (CODE);        break;
 
      case 'd': USE_BITS (RD);          break;
 
      case 'h': USE_BITS (PREFX);       break;
 
      case 'i': USE_BITS (IMMEDIATE);   break;
 
      case 'j': USE_BITS (DELTA);       break;
 
      case 'k': USE_BITS (CACHE);       break;
 
      case 'n': USE_BITS (RT);          break;
 
      case 'o': USE_BITS (DELTA);       break;
 
      case 'p': USE_BITS (DELTA);       break;
 
      case 'q': USE_BITS (CODE2);       break;
 
      case 'r': USE_BITS (RS);          break;
 
      case 's': USE_BITS (RS);          break;
 
      case 't': USE_BITS (RT);          break;
 
      case 'u': USE_BITS (IMMEDIATE);   break;
 
      case 'v': USE_BITS (RS);          break;
 
      case 'w': USE_BITS (RT);          break;
 
      case 'y': USE_BITS (RS3);         break;
 
      case 'z': break;
 
      case '|': USE_BITS (TRAP);        break;
 
      case '~': USE_BITS (OFFSET12);    break;
 
      default:
 
        as_bad (_("Internal error: bad microMIPS opcode "
 
                  "(unknown operand type `%c'): %s %s"),
 
                c, opc->name, opc->args);
 
        return 0;
 
      }
 
#undef USE_BITS
 
  if (used_bits != insn_bits)
 
    {
 
      if (~used_bits & insn_bits)
 
        as_bad (_("Internal error: bad microMIPS opcode "
 
                  "(bits 0x%lx undefined): %s %s"),
 
                ~used_bits & insn_bits, opc->name, opc->args);
 
      if (used_bits & ~insn_bits)
 
        as_bad (_("Internal error: bad microMIPS opcode "
 
                  "(bits 0x%lx defined): %s %s"),
 
                used_bits & ~insn_bits, opc->name, opc->args);
 
      return 0;
 
    }
 
  return 1;
 
}
 
 
/* UDI immediates.  */
/* UDI immediates.  */
struct mips_immed {
struct mips_immed {
  char          type;
  char          type;
  unsigned int  shift;
  unsigned int  shift;
  unsigned long mask;
  unsigned long mask;
Line 8862... Line 10555...
    return 1;
    return 1;
 
 
  return 0;
  return 0;
}
}
 
 
 
/* Check if EXPR is a constant between MIN (inclusive) and MAX (exclusive)
 
   taking bits from BIT up.  */
 
static int
 
expr_const_in_range (expressionS *ep, offsetT min, offsetT max, int bit)
 
{
 
  return (ep->X_op == O_constant
 
          && (ep->X_add_number & ((1 << bit) - 1)) == 0
 
          && ep->X_add_number >= min << bit
 
          && ep->X_add_number < max << bit);
 
}
 
 
/* This routine assembles an instruction into its binary format.  As a
/* This routine assembles an instruction into its binary format.  As a
   side effect, it sets one of the global variables imm_reloc or
   side effect, it sets one of the global variables imm_reloc or
   offset_reloc to the type of relocation to do if one of the operands
   offset_reloc to the type of relocation to do if one of the operands
   is an address expression.  */
   is an address expression.  */
 
 
static void
static void
mips_ip (char *str, struct mips_cl_insn *ip)
mips_ip (char *str, struct mips_cl_insn *ip)
{
{
 
  bfd_boolean wrong_delay_slot_insns = FALSE;
 
  bfd_boolean need_delay_slot_ok = TRUE;
 
  struct mips_opcode *firstinsn = NULL;
 
  const struct mips_opcode *past;
 
  struct hash_control *hash;
  char *s;
  char *s;
  const char *args;
  const char *args;
  char c = 0;
  char c = 0;
  struct mips_opcode *insn;
  struct mips_opcode *insn;
  char *argsStart;
  char *argsStart;
  unsigned int regno;
  unsigned int regno;
  unsigned int lastregno;
  unsigned int lastregno;
 
  unsigned int destregno = 0;
  unsigned int lastpos = 0;
  unsigned int lastpos = 0;
  unsigned int limlo, limhi;
  unsigned int limlo, limhi;
  char *s_reset;
  char *s_reset;
  char save_c = 0;
 
  offsetT min_range, max_range;
  offsetT min_range, max_range;
 
  long opend;
 
  char *name;
  int argnum;
  int argnum;
  unsigned int rtype;
  unsigned int rtype;
 
  char *dot;
 
  long end;
 
 
  insn_error = NULL;
  insn_error = NULL;
 
 
  /* If the instruction contains a '.', we first try to match an instruction
  if (mips_opts.micromips)
     including the '.'.  Then we try again without the '.'.  */
 
  insn = NULL;
 
  for (s = str; *s != '\0' && !ISSPACE (*s); ++s)
 
    continue;
 
 
 
  /* If we stopped on whitespace, then replace the whitespace with null for
 
     the call to hash_find.  Save the character we replaced just in case we
 
     have to re-parse the instruction.  */
 
  if (ISSPACE (*s))
 
    {
    {
      save_c = *s;
      hash = micromips_op_hash;
      *s++ = '\0';
      past = &micromips_opcodes[bfd_micromips_num_opcodes];
    }
    }
 
  else
  insn = (struct mips_opcode *) hash_find (op_hash, str);
 
 
 
  /* If we didn't find the instruction in the opcode table, try again, but
 
     this time with just the instruction up to, but not including the
 
     first '.'.  */
 
  if (insn == NULL)
 
    {
    {
      /* Restore the character we overwrite above (if any).  */
      hash = op_hash;
      if (save_c)
      past = &mips_opcodes[NUMOPCODES];
        *(--s) = save_c;
    }
 
  forced_insn_length = 0;
      /* Scan up to the first '.' or whitespace.  */
  insn = NULL;
      for (s = str;
 
           *s != '\0' && *s != '.' && !ISSPACE (*s);
  /* We first try to match an instruction up to a space or to the end.  */
           ++s)
  for (end = 0; str[end] != '\0' && !ISSPACE (str[end]); end++)
        continue;
        continue;
 
 
      /* If we did not find a '.', then we can quit now.  */
  /* Make a copy of the instruction so that we can fiddle with it.  */
      if (*s != '.')
  name = alloca (end + 1);
 
  memcpy (name, str, end);
 
  name[end] = '\0';
 
 
 
  for (;;)
        {
        {
          insn_error = _("Unrecognized opcode");
      insn = (struct mips_opcode *) hash_find (hash, name);
          return;
 
        }
 
 
 
      /* Lookup the instruction in the hash table.  */
      if (insn != NULL || !mips_opts.micromips)
      *s++ = '\0';
        break;
      if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
      if (forced_insn_length)
 
        break;
 
 
 
      /* See if there's an instruction size override suffix,
 
         either `16' or `32', at the end of the mnemonic proper,
 
         that defines the operation, i.e. before the first `.'
 
         character if any.  Strip it and retry.  */
 
      dot = strchr (name, '.');
 
      opend = dot != NULL ? dot - name : end;
 
      if (opend < 3)
 
        break;
 
      if (name[opend - 2] == '1' && name[opend - 1] == '6')
 
        forced_insn_length = 2;
 
      else if (name[opend - 2] == '3' && name[opend - 1] == '2')
 
        forced_insn_length = 4;
 
      else
 
        break;
 
      memcpy (name + opend - 2, name + opend, end - opend + 1);
 
    }
 
  if (insn == NULL)
        {
        {
          insn_error = _("Unrecognized opcode");
          insn_error = _("Unrecognized opcode");
          return;
          return;
        }
        }
    }
 
 
 
  argsStart = s;
  /* For microMIPS instructions placed in a fixed-length branch delay slot
 
     we make up to two passes over the relevant fragment of the opcode
 
     table.  First we try instructions that meet the delay slot's length
 
     requirement.  If none matched, then we retry with the remaining ones
 
     and if one matches, then we use it and then issue an appropriate
 
     warning later on.  */
 
  argsStart = s = str + end;
  for (;;)
  for (;;)
    {
    {
 
      bfd_boolean delay_slot_ok;
 
      bfd_boolean size_ok;
      bfd_boolean ok;
      bfd_boolean ok;
 
 
      gas_assert (strcmp (insn->name, str) == 0);
      gas_assert (strcmp (insn->name, name) == 0);
 
 
      ok = is_opcode_valid (insn);
      ok = is_opcode_valid (insn);
      if (! ok)
      size_ok = is_size_valid (insn);
 
      delay_slot_ok = is_delay_slot_valid (insn);
 
      if (!delay_slot_ok && !wrong_delay_slot_insns)
        {
        {
          if (insn + 1 < &mips_opcodes[NUMOPCODES]
          firstinsn = insn;
              && strcmp (insn->name, insn[1].name) == 0)
          wrong_delay_slot_insns = TRUE;
 
        }
 
      if (!ok || !size_ok || delay_slot_ok != need_delay_slot_ok)
 
        {
 
          static char buf[256];
 
 
 
          if (insn + 1 < past && strcmp (insn->name, insn[1].name) == 0)
            {
            {
              ++insn;
              ++insn;
              continue;
              continue;
            }
            }
          else
          if (wrong_delay_slot_insns && need_delay_slot_ok)
            {
 
              if (!insn_error)
 
                {
                {
                  static char buf[100];
              gas_assert (firstinsn);
                  sprintf (buf,
              need_delay_slot_ok = FALSE;
                           _("opcode not supported on this processor: %s (%s)"),
              past = insn + 1;
 
              insn = firstinsn;
 
              continue;
 
            }
 
 
 
          if (insn_error)
 
            return;
 
 
 
          if (!ok)
 
            sprintf (buf, _("opcode not supported on this processor: %s (%s)"),
                           mips_cpu_info_from_arch (mips_opts.arch)->name,
                           mips_cpu_info_from_arch (mips_opts.arch)->name,
                           mips_cpu_info_from_isa (mips_opts.isa)->name);
                           mips_cpu_info_from_isa (mips_opts.isa)->name);
 
          else
 
            sprintf (buf, _("Unrecognized %u-bit version of microMIPS opcode"),
 
                     8 * forced_insn_length);
                  insn_error = buf;
                  insn_error = buf;
                }
 
              if (save_c)
 
                *(--s) = save_c;
 
              return;
              return;
            }
            }
        }
 
 
 
      create_insn (ip, insn);
      create_insn (ip, insn);
      insn_error = NULL;
      insn_error = NULL;
      argnum = 1;
      argnum = 1;
      lastregno = 0xffffffff;
      lastregno = 0xffffffff;
Line 8986... Line 10727...
              if (*s == '\0')
              if (*s == '\0')
                return;
                return;
              break;
              break;
 
 
            case '2': /* DSP 2-bit unsigned immediate in bit 11.  */
            case '2': /* DSP 2-bit unsigned immediate in bit 11.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number != 1
              if ((unsigned long) imm_expr.X_add_number != 1
                  && (unsigned long) imm_expr.X_add_number != 3)
                  && (unsigned long) imm_expr.X_add_number != 3)
                {
                {
                  as_bad (_("BALIGN immediate not 1 or 3 (%lu)"),
                  as_bad (_("BALIGN immediate not 1 or 3 (%lu)"),
                          (unsigned long) imm_expr.X_add_number);
                          (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (BP, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, BP, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '3': /* DSP 3-bit unsigned immediate in bit 21.  */
            case '3': /* DSP 3-bit unsigned immediate in bit 21.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_SA3)
              if (imm_expr.X_add_number & ~OP_MASK_SA3)
                {
                {
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                          OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
                          OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (SA3, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, SA3, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '4': /* DSP 4-bit unsigned immediate in bit 21.  */
            case '4': /* DSP 4-bit unsigned immediate in bit 21.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_SA4)
              if (imm_expr.X_add_number & ~OP_MASK_SA4)
                {
                {
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                          OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
                          OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (SA4, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, SA4, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '5': /* DSP 8-bit unsigned immediate in bit 16.  */
            case '5': /* DSP 8-bit unsigned immediate in bit 16.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_IMM8)
              if (imm_expr.X_add_number & ~OP_MASK_IMM8)
                {
                {
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                          OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
                          OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (IMM8, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, IMM8, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '6': /* DSP 5-bit unsigned immediate in bit 21.  */
            case '6': /* DSP 5-bit unsigned immediate in bit 21.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_RS)
              if (imm_expr.X_add_number & ~OP_MASK_RS)
                {
                {
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                          OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
                          OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (RS, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, RS, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '7': /* Four DSP accumulators in bits 11,12.  */
            case '7': /* Four DSP accumulators in bits 11,12.  */
 
              gas_assert (!mips_opts.micromips);
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                  s[3] >= '0' && s[3] <= '3')
                {
                {
                  regno = s[3] - '0';
                  regno = s[3] - '0';
                  s += 4;
                  s += 4;
                  INSERT_OPERAND (DSPACC, *ip, regno);
                  INSERT_OPERAND (0, DSPACC, *ip, regno);
                  continue;
                  continue;
                }
                }
              else
              else
                as_bad (_("Invalid dsp acc register"));
                as_bad (_("Invalid dsp acc register"));
              break;
              break;
 
 
            case '8': /* DSP 6-bit unsigned immediate in bit 11.  */
            case '8': /* DSP 6-bit unsigned immediate in bit 11.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
              if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
                {
                {
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                          OP_MASK_WRDSP,
                          OP_MASK_WRDSP,
                          (unsigned long) imm_expr.X_add_number);
                          (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (WRDSP, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, WRDSP, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '9': /* Four DSP accumulators in bits 21,22.  */
            case '9': /* Four DSP accumulators in bits 21,22.  */
 
              gas_assert (!mips_opts.micromips);
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                  s[3] >= '0' && s[3] <= '3')
                {
                {
                  regno = s[3] - '0';
                  regno = s[3] - '0';
                  s += 4;
                  s += 4;
                  INSERT_OPERAND (DSPACC_S, *ip, regno);
                  INSERT_OPERAND (0, DSPACC_S, *ip, regno);
                  continue;
                  continue;
                }
                }
              else
              else
                as_bad (_("Invalid dsp acc register"));
                as_bad (_("Invalid dsp acc register"));
              break;
              break;
 
 
            case '0': /* DSP 6-bit signed immediate in bit 20.  */
            case '0': /* DSP 6-bit signed immediate in bit 20.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              min_range = -((OP_MASK_DSPSFT + 1) >> 1);
              min_range = -((OP_MASK_DSPSFT + 1) >> 1);
              max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
              max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
              if (imm_expr.X_add_number < min_range ||
              if (imm_expr.X_add_number < min_range ||
Line 9103... Line 10853...
                {
                {
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                          (long) min_range, (long) max_range,
                          (long) min_range, (long) max_range,
                          (long) imm_expr.X_add_number);
                          (long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (DSPSFT, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, DSPSFT, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '\'': /* DSP 6-bit unsigned immediate in bit 16.  */
            case '\'': /* DSP 6-bit unsigned immediate in bit 16.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
              if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
                {
                {
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
                          OP_MASK_RDDSP,
                          OP_MASK_RDDSP,
                          (unsigned long) imm_expr.X_add_number);
                          (unsigned long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (RDDSP, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, RDDSP, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case ':': /* DSP 7-bit signed immediate in bit 19.  */
            case ':': /* DSP 7-bit signed immediate in bit 19.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
              min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
              max_range = ((OP_MASK_DSPSFT_7 + 1) >> 1) - 1;
              max_range = ((OP_MASK_DSPSFT_7 + 1) >> 1) - 1;
              if (imm_expr.X_add_number < min_range ||
              if (imm_expr.X_add_number < min_range ||
Line 9134... Line 10886...
                {
                {
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                          (long) min_range, (long) max_range,
                          (long) min_range, (long) max_range,
                          (long) imm_expr.X_add_number);
                          (long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (DSPSFT_7, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, DSPSFT_7, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '@': /* DSP 10-bit signed immediate in bit 16.  */
            case '@': /* DSP 10-bit signed immediate in bit 16.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              min_range = -((OP_MASK_IMM10 + 1) >> 1);
              min_range = -((OP_MASK_IMM10 + 1) >> 1);
              max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
              max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
              if (imm_expr.X_add_number < min_range ||
              if (imm_expr.X_add_number < min_range ||
Line 9151... Line 10904...
                {
                {
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
                          (long) min_range, (long) max_range,
                          (long) min_range, (long) max_range,
                          (long) imm_expr.X_add_number);
                          (long) imm_expr.X_add_number);
                }
                }
              INSERT_OPERAND (IMM10, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, IMM10, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '!': /* MT usermode flag bit.  */
            case '!': /* MT usermode flag bit.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_MT_U)
              if (imm_expr.X_add_number & ~OP_MASK_MT_U)
                as_bad (_("MT usermode bit not 0 or 1 (%lu)"),
                as_bad (_("MT usermode bit not 0 or 1 (%lu)"),
                        (unsigned long) imm_expr.X_add_number);
                        (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (MT_U, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, MT_U, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '$': /* MT load high flag bit.  */
            case '$': /* MT load high flag bit.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number & ~OP_MASK_MT_H)
              if (imm_expr.X_add_number & ~OP_MASK_MT_H)
                as_bad (_("MT load high bit not 0 or 1 (%lu)"),
                as_bad (_("MT load high bit not 0 or 1 (%lu)"),
                        (unsigned long) imm_expr.X_add_number);
                        (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (MT_H, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, MT_H, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '*': /* Four DSP accumulators in bits 18,19.  */
            case '*': /* Four DSP accumulators in bits 18,19.  */
 
              gas_assert (!mips_opts.micromips);
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                  s[3] >= '0' && s[3] <= '3')
                {
                {
                  regno = s[3] - '0';
                  regno = s[3] - '0';
                  s += 4;
                  s += 4;
                  INSERT_OPERAND (MTACC_T, *ip, regno);
                  INSERT_OPERAND (0, MTACC_T, *ip, regno);
                  continue;
                  continue;
                }
                }
              else
              else
                as_bad (_("Invalid dsp/smartmips acc register"));
                as_bad (_("Invalid dsp/smartmips acc register"));
              break;
              break;
 
 
            case '&': /* Four DSP accumulators in bits 13,14.  */
            case '&': /* Four DSP accumulators in bits 13,14.  */
 
              gas_assert (!mips_opts.micromips);
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
              if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
                  s[3] >= '0' && s[3] <= '3')
                  s[3] >= '0' && s[3] <= '3')
                {
                {
                  regno = s[3] - '0';
                  regno = s[3] - '0';
                  s += 4;
                  s += 4;
                  INSERT_OPERAND (MTACC_D, *ip, regno);
                  INSERT_OPERAND (0, MTACC_D, *ip, regno);
                  continue;
                  continue;
                }
                }
              else
              else
                as_bad (_("Invalid dsp/smartmips acc register"));
                as_bad (_("Invalid dsp/smartmips acc register"));
              break;
              break;
 
 
 
            case '\\':          /* 3-bit bit position.  */
 
              {
 
                unsigned long mask = (!mips_opts.micromips
 
                                      ? OP_MASK_3BITPOS
 
                                      : MICROMIPSOP_MASK_3BITPOS);
 
 
 
                my_getExpression (&imm_expr, s);
 
                check_absolute_expr (ip, &imm_expr);
 
                if ((unsigned long) imm_expr.X_add_number > mask)
 
                  as_warn (_("Bit position for %s not in range 0..%lu (%lu)"),
 
                           ip->insn_mo->name,
 
                           mask, (unsigned long) imm_expr.X_add_number);
 
                INSERT_OPERAND (mips_opts.micromips,
 
                                3BITPOS, *ip, imm_expr.X_add_number);
 
                imm_expr.X_op = O_absent;
 
                s = expr_end;
 
              }
 
              continue;
 
 
            case ',':
            case ',':
              ++argnum;
              ++argnum;
              if (*s++ == *args)
              if (*s++ == *args)
                continue;
                continue;
              s--;
              s--;
              switch (*++args)
              switch (*++args)
                {
                {
                case 'r':
                case 'r':
                case 'v':
                case 'v':
                  INSERT_OPERAND (RS, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, RS, *ip, lastregno);
                  continue;
                  continue;
 
 
                case 'w':
                case 'w':
                  INSERT_OPERAND (RT, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, RT, *ip, lastregno);
                  continue;
                  continue;
 
 
                case 'W':
                case 'W':
                  INSERT_OPERAND (FT, *ip, lastregno);
                  gas_assert (!mips_opts.micromips);
 
                  INSERT_OPERAND (0, FT, *ip, lastregno);
                  continue;
                  continue;
 
 
                case 'V':
                case 'V':
                  INSERT_OPERAND (FS, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, FS, *ip, lastregno);
                  continue;
                  continue;
                }
                }
              break;
              break;
 
 
            case '(':
            case '(':
              /* Handle optional base register.
              /* Handle optional base register.
                 Either the base register is omitted or
                 Either the base register is omitted or
                 we must have a left paren.  */
                 we must have a left paren.  */
              /* This is dependent on the next operand specifier
              /* This is dependent on the next operand specifier
                 is a base register specification.  */
                 is a base register specification.  */
              gas_assert (args[1] == 'b');
              gas_assert (args[1] == 'b'
              if (*s == '\0')
                          || (mips_opts.micromips
 
                              && args[1] == 'm'
 
                              && (args[2] == 'l' || args[2] == 'n'
 
                                  || args[2] == 's' || args[2] == 'a')));
 
              if (*s == '\0' && args[1] == 'b')
                return;
                return;
 
              /* Fall through.  */
 
 
            case ')':           /* These must match exactly.  */
            case ')':           /* These must match exactly.  */
            case '[':
              if (*s++ == *args)
 
                continue;
 
              break;
 
 
 
            case '[':           /* These must match exactly.  */
            case ']':
            case ']':
 
              gas_assert (!mips_opts.micromips);
              if (*s++ == *args)
              if (*s++ == *args)
                continue;
                continue;
              break;
              break;
 
 
            case '+':           /* Opcode extension character.  */
            case '+':           /* Opcode extension character.  */
Line 9254... Line 11041...
                {
                {
                case '1':       /* UDI immediates.  */
                case '1':       /* UDI immediates.  */
                case '2':
                case '2':
                case '3':
                case '3':
                case '4':
                case '4':
 
                  gas_assert (!mips_opts.micromips);
                  {
                  {
                    const struct mips_immed *imm = mips_immed;
                    const struct mips_immed *imm = mips_immed;
 
 
                    while (imm->type && imm->type != *args)
                    while (imm->type && imm->type != *args)
                      ++imm;
                      ++imm;
Line 9297... Line 11085...
                      as_bad (_("Improper position (%lu)"),
                      as_bad (_("Improper position (%lu)"),
                              (unsigned long) imm_expr.X_add_number);
                              (unsigned long) imm_expr.X_add_number);
                      imm_expr.X_add_number = limlo;
                      imm_expr.X_add_number = limlo;
                    }
                    }
                  lastpos = imm_expr.X_add_number;
                  lastpos = imm_expr.X_add_number;
                  INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (mips_opts.micromips,
 
                                  EXTLSB, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'B':               /* ins size, becomes MSB.  */
                case 'B':               /* ins size, becomes MSB.  */
Line 9328... Line 11117...
                      as_bad (_("Improper insert size (%lu, position %lu)"),
                      as_bad (_("Improper insert size (%lu, position %lu)"),
                              (unsigned long) imm_expr.X_add_number,
                              (unsigned long) imm_expr.X_add_number,
                              (unsigned long) lastpos);
                              (unsigned long) lastpos);
                      imm_expr.X_add_number = limlo - lastpos;
                      imm_expr.X_add_number = limlo - lastpos;
                    }
                    }
                  INSERT_OPERAND (INSMSB, *ip,
                  INSERT_OPERAND (mips_opts.micromips, INSMSB, *ip,
                                 lastpos + imm_expr.X_add_number - 1);
                                 lastpos + imm_expr.X_add_number - 1);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
Line 9364... Line 11153...
                      as_bad (_("Improper extract size (%lu, position %lu)"),
                      as_bad (_("Improper extract size (%lu, position %lu)"),
                              (unsigned long) imm_expr.X_add_number,
                              (unsigned long) imm_expr.X_add_number,
                              (unsigned long) lastpos);
                              (unsigned long) lastpos);
                      imm_expr.X_add_number = limlo - lastpos;
                      imm_expr.X_add_number = limlo - lastpos;
                    }
                    }
                  INSERT_OPERAND (EXTMSBD, *ip, imm_expr.X_add_number - 1);
                  INSERT_OPERAND (mips_opts.micromips,
 
                                  EXTMSBD, *ip, imm_expr.X_add_number - 1);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'D':
                case 'D':
Line 9385... Line 11175...
                    normalize_constant_expr (&imm2_expr);
                    normalize_constant_expr (&imm2_expr);
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'T': /* Coprocessor register.  */
                case 'T': /* Coprocessor register.  */
 
                  gas_assert (!mips_opts.micromips);
                  /* +T is for disassembly only; never match.  */
                  /* +T is for disassembly only; never match.  */
                  break;
                  break;
 
 
                case 't': /* Coprocessor register number.  */
                case 't': /* Coprocessor register number.  */
 
                  gas_assert (!mips_opts.micromips);
                  if (s[0] == '$' && ISDIGIT (s[1]))
                  if (s[0] == '$' && ISDIGIT (s[1]))
                    {
                    {
                      ++s;
                      ++s;
                      regno = 0;
                      regno = 0;
                      do
                      do
Line 9404... Line 11196...
                      while (ISDIGIT (*s));
                      while (ISDIGIT (*s));
                      if (regno > 31)
                      if (regno > 31)
                        as_bad (_("Invalid register number (%d)"), regno);
                        as_bad (_("Invalid register number (%d)"), regno);
                      else
                      else
                        {
                        {
                          INSERT_OPERAND (RT, *ip, regno);
                          INSERT_OPERAND (0, RT, *ip, regno);
                          continue;
                          continue;
                        }
                        }
                    }
                    }
                  else
                  else
                    as_bad (_("Invalid coprocessor 0 register number"));
                    as_bad (_("Invalid coprocessor 0 register number"));
                  break;
                  break;
 
 
                case 'x':
                case 'x':
                  /* bbit[01] and bbit[01]32 bit index.  Give error if index
                  /* bbit[01] and bbit[01]32 bit index.  Give error if index
                     is not in the valid range.  */
                     is not in the valid range.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned) imm_expr.X_add_number > 31)
                  if ((unsigned) imm_expr.X_add_number > 31)
                    {
                    {
                      as_bad (_("Improper bit index (%lu)"),
                      as_bad (_("Improper bit index (%lu)"),
                              (unsigned long) imm_expr.X_add_number);
                              (unsigned long) imm_expr.X_add_number);
                      imm_expr.X_add_number = 0;
                      imm_expr.X_add_number = 0;
                    }
                    }
                  INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, BBITIND, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'X':
                case 'X':
                  /* bbit[01] bit index when bbit is used but we generate
                  /* bbit[01] bit index when bbit is used but we generate
                     bbit[01]32 because the index is over 32.  Move to the
                     bbit[01]32 because the index is over 32.  Move to the
                     next candidate if index is not in the valid range.  */
                     next candidate if index is not in the valid range.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned) imm_expr.X_add_number < 32
                  if ((unsigned) imm_expr.X_add_number < 32
                      || (unsigned) imm_expr.X_add_number > 63)
                      || (unsigned) imm_expr.X_add_number > 63)
                    break;
                    break;
                  INSERT_OPERAND (BBITIND, *ip, imm_expr.X_add_number - 32);
                  INSERT_OPERAND (0, BBITIND, *ip, imm_expr.X_add_number - 32);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'p':
                case 'p':
                  /* cins, cins32, exts and exts32 position field.  Give error
                  /* cins, cins32, exts and exts32 position field.  Give error
                     if it's not in the valid range.  */
                     if it's not in the valid range.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned) imm_expr.X_add_number > 31)
                  if ((unsigned) imm_expr.X_add_number > 31)
                    {
                    {
                      as_bad (_("Improper position (%lu)"),
                      as_bad (_("Improper position (%lu)"),
                              (unsigned long) imm_expr.X_add_number);
                              (unsigned long) imm_expr.X_add_number);
                      imm_expr.X_add_number = 0;
                      imm_expr.X_add_number = 0;
                    }
                    }
                  /* Make the pos explicit to simplify +S.  */
                  /* Make the pos explicit to simplify +S.  */
                  lastpos = imm_expr.X_add_number + 32;
                  lastpos = imm_expr.X_add_number + 32;
                  INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, CINSPOS, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'P':
                case 'P':
                  /* cins, cins32, exts and exts32 position field.  Move to
                  /* cins, cins32, exts and exts32 position field.  Move to
                     the next candidate if it's not in the valid range.  */
                     the next candidate if it's not in the valid range.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned) imm_expr.X_add_number < 32
                  if ((unsigned) imm_expr.X_add_number < 32
                      || (unsigned) imm_expr.X_add_number > 63)
                      || (unsigned) imm_expr.X_add_number > 63)
                    break;
                    break;
                  lastpos = imm_expr.X_add_number;
                  lastpos = imm_expr.X_add_number;
                  INSERT_OPERAND (CINSPOS, *ip, imm_expr.X_add_number - 32);
                  INSERT_OPERAND (0, CINSPOS, *ip, imm_expr.X_add_number - 32);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 's':
                case 's':
                  /* cins and exts length-minus-one field.  */
                  /* cins and exts length-minus-one field.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned long) imm_expr.X_add_number > 31)
                  if ((unsigned long) imm_expr.X_add_number > 31)
                    {
                    {
                      as_bad (_("Improper size (%lu)"),
                      as_bad (_("Improper size (%lu)"),
                              (unsigned long) imm_expr.X_add_number);
                              (unsigned long) imm_expr.X_add_number);
                      imm_expr.X_add_number = 0;
                      imm_expr.X_add_number = 0;
                    }
                    }
                  INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, CINSLM1, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'S':
                case 'S':
                  /* cins32/exts32 and cins/exts aliasing cint32/exts32
                  /* cins32/exts32 and cins/exts aliasing cint32/exts32
                     length-minus-one field.  */
                     length-minus-one field.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((long) imm_expr.X_add_number < 0
                  if ((long) imm_expr.X_add_number < 0
                      || (unsigned long) imm_expr.X_add_number + lastpos > 63)
                      || (unsigned long) imm_expr.X_add_number + lastpos > 63)
                    {
                    {
                      as_bad (_("Improper size (%lu)"),
                      as_bad (_("Improper size (%lu)"),
                              (unsigned long) imm_expr.X_add_number);
                              (unsigned long) imm_expr.X_add_number);
                      imm_expr.X_add_number = 0;
                      imm_expr.X_add_number = 0;
                    }
                    }
                  INSERT_OPERAND (CINSLM1, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, CINSLM1, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'Q':
                case 'Q':
                  /* seqi/snei immediate field.  */
                  /* seqi/snei immediate field.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((long) imm_expr.X_add_number < -512
                  if ((long) imm_expr.X_add_number < -512
                      || (long) imm_expr.X_add_number >= 512)
                      || (long) imm_expr.X_add_number >= 512)
                    {
                    {
                      as_bad (_("Improper immediate (%ld)"),
                      as_bad (_("Improper immediate (%ld)"),
                               (long) imm_expr.X_add_number);
                               (long) imm_expr.X_add_number);
                      imm_expr.X_add_number = 0;
                      imm_expr.X_add_number = 0;
                    }
                    }
                  INSERT_OPERAND (SEQI, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, SEQI, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'a': /* 8-bit signed offset in bit 6 */
                case 'a': /* 8-bit signed offset in bit 6 */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  min_range = -((OP_MASK_OFFSET_A + 1) >> 1);
                  min_range = -((OP_MASK_OFFSET_A + 1) >> 1);
                  max_range = ((OP_MASK_OFFSET_A + 1) >> 1) - 1;
                  max_range = ((OP_MASK_OFFSET_A + 1) >> 1) - 1;
                  if (imm_expr.X_add_number < min_range
                  if (imm_expr.X_add_number < min_range
Line 9534... Line 11334...
                    {
                    {
                      as_bad (_("Offset not in range %ld..%ld (%ld)"),
                      as_bad (_("Offset not in range %ld..%ld (%ld)"),
                              (long) min_range, (long) max_range,
                              (long) min_range, (long) max_range,
                              (long) imm_expr.X_add_number);
                              (long) imm_expr.X_add_number);
                    }
                    }
                  INSERT_OPERAND (OFFSET_A, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, OFFSET_A, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'b': /* 8-bit signed offset in bit 3 */
                case 'b': /* 8-bit signed offset in bit 3 */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  min_range = -((OP_MASK_OFFSET_B + 1) >> 1);
                  min_range = -((OP_MASK_OFFSET_B + 1) >> 1);
                  max_range = ((OP_MASK_OFFSET_B + 1) >> 1) - 1;
                  max_range = ((OP_MASK_OFFSET_B + 1) >> 1) - 1;
                  if (imm_expr.X_add_number < min_range
                  if (imm_expr.X_add_number < min_range
Line 9551... Line 11352...
                    {
                    {
                      as_bad (_("Offset not in range %ld..%ld (%ld)"),
                      as_bad (_("Offset not in range %ld..%ld (%ld)"),
                              (long) min_range, (long) max_range,
                              (long) min_range, (long) max_range,
                              (long) imm_expr.X_add_number);
                              (long) imm_expr.X_add_number);
                    }
                    }
                  INSERT_OPERAND (OFFSET_B, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, OFFSET_B, *ip, imm_expr.X_add_number);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'c': /* 9-bit signed offset in bit 6 */
                case 'c': /* 9-bit signed offset in bit 6 */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  min_range = -((OP_MASK_OFFSET_C + 1) >> 1);
                  min_range = -((OP_MASK_OFFSET_C + 1) >> 1);
                  max_range = ((OP_MASK_OFFSET_C + 1) >> 1) - 1;
                  max_range = ((OP_MASK_OFFSET_C + 1) >> 1) - 1;
                  /* We check the offset range before adjusted.  */
                  /* We check the offset range before adjusted.  */
Line 9577... Line 11379...
                    {
                    {
                      as_bad (_("Offset not 16 bytes alignment (%ld)"),
                      as_bad (_("Offset not 16 bytes alignment (%ld)"),
                              (long) imm_expr.X_add_number);
                              (long) imm_expr.X_add_number);
                    }
                    }
                  /* Right shift 4 bits to adjust the offset operand.  */
                  /* Right shift 4 bits to adjust the offset operand.  */
                  INSERT_OPERAND (OFFSET_C, *ip, imm_expr.X_add_number >> 4);
                  INSERT_OPERAND (0, OFFSET_C, *ip,
 
                                  imm_expr.X_add_number >> 4);
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
                  s = expr_end;
                  s = expr_end;
                  continue;
                  continue;
 
 
                case 'z':
                case 'z':
 
                  gas_assert (!mips_opts.micromips);
                  if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
                  if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
                    break;
                    break;
                  if (regno == AT && mips_opts.at)
                  if (regno == AT && mips_opts.at)
                    {
                    {
                      if (mips_opts.at == ATREG)
                      if (mips_opts.at == ATREG)
                        as_warn (_("used $at without \".set noat\""));
                        as_warn (_("used $at without \".set noat\""));
                      else
                      else
                        as_warn (_("used $%u with \".set at=$%u\""),
                        as_warn (_("used $%u with \".set at=$%u\""),
                                 regno, mips_opts.at);
                                 regno, mips_opts.at);
                    }
                    }
                  INSERT_OPERAND (RZ, *ip, regno);
                  INSERT_OPERAND (0, RZ, *ip, regno);
                  continue;
                  continue;
 
 
                case 'Z':
                case 'Z':
 
                  gas_assert (!mips_opts.micromips);
                  if (!reg_lookup (&s, RTYPE_FPU, &regno))
                  if (!reg_lookup (&s, RTYPE_FPU, &regno))
                    break;
                    break;
                  INSERT_OPERAND (FZ, *ip, regno);
                  INSERT_OPERAND (0, FZ, *ip, regno);
                  continue;
                  continue;
 
 
                default:
                default:
                  as_bad (_("Internal error: bad mips opcode "
                  as_bad (_("Internal error: bad %s opcode "
                            "(unknown extension operand type `+%c'): %s %s"),
                            "(unknown extension operand type `+%c'): %s %s"),
 
                          mips_opts.micromips ? "microMIPS" : "MIPS",
                          *args, insn->name, insn->args);
                          *args, insn->name, insn->args);
                  /* Further processing is fruitless.  */
                  /* Further processing is fruitless.  */
                  return;
                  return;
                }
                }
              break;
              break;
 
 
 
            case '.':           /* 10-bit offset.  */
 
              gas_assert (mips_opts.micromips);
 
            case '~':           /* 12-bit offset.  */
 
              {
 
                int shift = *args == '.' ? 9 : 11;
 
                size_t i;
 
 
 
                /* Check whether there is only a single bracketed expression
 
                   left.  If so, it must be the base register and the
 
                   constant must be zero.  */
 
                if (*s == '(' && strchr (s + 1, '(') == 0)
 
                  continue;
 
 
 
                /* If this value won't fit into the offset, then go find
 
                   a macro that will generate a 16- or 32-bit offset code
 
                   pattern.  */
 
                i = my_getSmallExpression (&imm_expr, imm_reloc, s);
 
                if ((i == 0 && (imm_expr.X_op != O_constant
 
                                || imm_expr.X_add_number >= 1 << shift
 
                                || imm_expr.X_add_number < -1 << shift))
 
                    || i > 0)
 
                  {
 
                    imm_expr.X_op = O_absent;
 
                    break;
 
                  }
 
                if (shift == 9)
 
                  INSERT_OPERAND (1, OFFSET10, *ip, imm_expr.X_add_number);
 
                else
 
                  INSERT_OPERAND (mips_opts.micromips,
 
                                  OFFSET12, *ip, imm_expr.X_add_number);
 
                imm_expr.X_op = O_absent;
 
                s = expr_end;
 
              }
 
              continue;
 
 
            case '<':           /* must be at least one digit */
            case '<':           /* must be at least one digit */
              /*
              /*
               * According to the manual, if the shift amount is greater
               * According to the manual, if the shift amount is greater
               * than 31 or less than 0, then the shift amount should be
               * than 31 or less than 0, then the shift amount should be
               * mod 32.  In reality the mips assembler issues an error.
               * mod 32.  In reality the mips assembler issues an error.
Line 9623... Line 11464...
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
              if ((unsigned long) imm_expr.X_add_number > 31)
                as_warn (_("Improper shift amount (%lu)"),
                as_warn (_("Improper shift amount (%lu)"),
                         (unsigned long) imm_expr.X_add_number);
                         (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (mips_opts.micromips,
 
                              SHAMT, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case '>':           /* shift amount minus 32 */
            case '>':           /* shift amount minus 32 */
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number < 32
              if ((unsigned long) imm_expr.X_add_number < 32
                  || (unsigned long) imm_expr.X_add_number > 63)
                  || (unsigned long) imm_expr.X_add_number > 63)
                break;
                break;
              INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number - 32);
              INSERT_OPERAND (mips_opts.micromips,
 
                              SHAMT, *ip, imm_expr.X_add_number - 32);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case 'k':           /* CACHE code.  */
            case 'k':           /* CACHE code.  */
Line 9648... Line 11491...
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > 31)
              if ((unsigned long) imm_expr.X_add_number > 31)
                as_warn (_("Invalid value for `%s' (%lu)"),
                as_warn (_("Invalid value for `%s' (%lu)"),
                         ip->insn_mo->name,
                         ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
                         (unsigned long) imm_expr.X_add_number);
              if (*args == 'k')
              switch (*args)
                {
                {
                  if (mips_fix_cn63xxp1 && strcmp ("pref", insn->name) == 0)
                case 'k':
 
                  if (mips_fix_cn63xxp1
 
                      && !mips_opts.micromips
 
                      && strcmp ("pref", insn->name) == 0)
                    switch (imm_expr.X_add_number)
                    switch (imm_expr.X_add_number)
                      {
                      {
                      case 5:
                      case 5:
                      case 25:
                      case 25:
                      case 26:
                      case 26:
Line 9667... Line 11513...
 
 
                      default:  /* The rest must be changed to 28.  */
                      default:  /* The rest must be changed to 28.  */
                        imm_expr.X_add_number = 28;
                        imm_expr.X_add_number = 28;
                        break;
                        break;
                      }
                      }
                  INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (mips_opts.micromips,
 
                                  CACHE, *ip, imm_expr.X_add_number);
 
                  break;
 
                case 'h':
 
                  INSERT_OPERAND (mips_opts.micromips,
 
                                  PREFX, *ip, imm_expr.X_add_number);
 
                  break;
 
                case '1':
 
                  INSERT_OPERAND (mips_opts.micromips,
 
                                  STYPE, *ip, imm_expr.X_add_number);
 
                  break;
                }
                }
              else if (*args == 'h')
 
                INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
 
              else
 
                INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
 
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case 'c':           /* BREAK code.  */
            case 'c':           /* BREAK code.  */
 
              {
 
                unsigned long mask = (mips_opts.micromips
 
                                      ? MICROMIPSOP_MASK_CODE
 
                                      : OP_MASK_CODE);
 
 
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE)
                if ((unsigned long) imm_expr.X_add_number > mask)
                as_warn (_("Code for %s not in range 0..1023 (%lu)"),
                  as_warn (_("Code for %s not in range 0..%lu (%lu)"),
                         ip->insn_mo->name,
                         ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
                           mask, (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (CODE, *ip, imm_expr.X_add_number);
                INSERT_OPERAND (mips_opts.micromips,
 
                                CODE, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
 
              }
              continue;
              continue;
 
 
            case 'q':           /* Lower BREAK code.  */
            case 'q':           /* Lower BREAK code.  */
 
              {
 
                unsigned long mask = (mips_opts.micromips
 
                                      ? MICROMIPSOP_MASK_CODE2
 
                                      : OP_MASK_CODE2);
 
 
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE2)
                if ((unsigned long) imm_expr.X_add_number > mask)
                as_warn (_("Lower code for %s not in range 0..1023 (%lu)"),
                  as_warn (_("Lower code for %s not in range 0..%lu (%lu)"),
                         ip->insn_mo->name,
                         ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
                           mask, (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (CODE2, *ip, imm_expr.X_add_number);
                INSERT_OPERAND (mips_opts.micromips,
 
                                CODE2, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
 
              }
              continue;
              continue;
 
 
            case 'B':           /* 20-bit SYSCALL/BREAK code.  */
            case 'B':           /* 20- or 10-bit syscall/break/wait code.  */
 
              {
 
                unsigned long mask = (mips_opts.micromips
 
                                      ? MICROMIPSOP_MASK_CODE10
 
                                      : OP_MASK_CODE20);
 
 
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
                if ((unsigned long) imm_expr.X_add_number > mask)
                as_warn (_("Code for %s not in range 0..1048575 (%lu)"),
                  as_warn (_("Code for %s not in range 0..%lu (%lu)"),
                         ip->insn_mo->name,
                         ip->insn_mo->name,
                         (unsigned long) imm_expr.X_add_number);
                           mask, (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (CODE20, *ip, imm_expr.X_add_number);
                if (mips_opts.micromips)
 
                  INSERT_OPERAND (1, CODE10, *ip, imm_expr.X_add_number);
 
                else
 
                  INSERT_OPERAND (0, CODE20, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
 
              }
              continue;
              continue;
 
 
            case 'C':           /* Coprocessor code.  */
            case 'C':           /* 25- or 23-bit coprocessor code.  */
 
              {
 
                unsigned long mask = (mips_opts.micromips
 
                                      ? MICROMIPSOP_MASK_COPZ
 
                                      : OP_MASK_COPZ);
 
 
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_COPZ)
                if ((unsigned long) imm_expr.X_add_number > mask)
                {
                  as_warn (_("Coproccesor code > %u bits (%lu)"),
                  as_warn (_("Coproccesor code > 25 bits (%lu)"),
                           mips_opts.micromips ? 23U : 25U,
                           (unsigned long) imm_expr.X_add_number);
                           (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= OP_MASK_COPZ;
                INSERT_OPERAND (mips_opts.micromips,
                }
                                COPZ, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (COPZ, *ip, imm_expr.X_add_number);
 
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
 
              }
              continue;
              continue;
 
 
            case 'J':           /* 19-bit WAIT code.  */
            case 'J':           /* 19-bit WAIT code.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
                {
                {
                  as_warn (_("Illegal 19-bit code (%lu)"),
                  as_warn (_("Illegal 19-bit code (%lu)"),
                           (unsigned long) imm_expr.X_add_number);
                           (unsigned long) imm_expr.X_add_number);
                  imm_expr.X_add_number &= OP_MASK_CODE19;
                  imm_expr.X_add_number &= OP_MASK_CODE19;
                }
                }
              INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, CODE19, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case 'P':           /* Performance register.  */
            case 'P':           /* Performance register.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
              if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
                as_warn (_("Invalid performance register (%lu)"),
                as_warn (_("Invalid performance register (%lu)"),
                         (unsigned long) imm_expr.X_add_number);
                         (unsigned long) imm_expr.X_add_number);
              INSERT_OPERAND (PERFREG, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, PERFREG, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case 'G':           /* Coprocessor destination register.  */
            case 'G':           /* Coprocessor destination register.  */
              if (((ip->insn_opcode >> OP_SH_OP) & OP_MASK_OP) == OP_OP_COP0)
              {
                ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, &regno);
                unsigned long opcode = ip->insn_opcode;
 
                unsigned long mask;
 
                unsigned int types;
 
                int cop0;
 
 
 
                if (mips_opts.micromips)
 
                  {
 
                    mask = ~((MICROMIPSOP_MASK_RT << MICROMIPSOP_SH_RT)
 
                             | (MICROMIPSOP_MASK_RS << MICROMIPSOP_SH_RS)
 
                             | (MICROMIPSOP_MASK_SEL << MICROMIPSOP_SH_SEL));
 
                    opcode &= mask;
 
                    switch (opcode)
 
                      {
 
                      case 0x000000fc:                          /* mfc0  */
 
                      case 0x000002fc:                          /* mtc0  */
 
                      case 0x580000fc:                          /* dmfc0 */
 
                      case 0x580002fc:                          /* dmtc0 */
 
                        cop0 = 1;
 
                        break;
 
                      default:
 
                        cop0 = 0;
 
                        break;
 
                      }
 
                  }
              else
              else
                ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
                  {
              INSERT_OPERAND (RD, *ip, regno);
                    opcode = (opcode >> OP_SH_OP) & OP_MASK_OP;
 
                    cop0 = opcode == OP_OP_COP0;
 
                  }
 
                types = RTYPE_NUM | (cop0 ? RTYPE_CP0 : RTYPE_GP);
 
                ok = reg_lookup (&s, types, &regno);
 
                if (mips_opts.micromips)
 
                  INSERT_OPERAND (1, RS, *ip, regno);
 
                else
 
                  INSERT_OPERAND (0, RD, *ip, regno);
              if (ok)
              if (ok)
                {
                {
                  lastregno = regno;
                  lastregno = regno;
                  continue;
                  continue;
                }
                }
              else
              }
                break;
                break;
 
 
 
            case 'y':           /* ALNV.PS source register.  */
 
              gas_assert (mips_opts.micromips);
 
              goto do_reg;
 
            case 'x':           /* Ignore register name.  */
 
            case 'U':           /* Destination register (CLO/CLZ).  */
 
            case 'g':           /* Coprocessor destination register.  */
 
              gas_assert (!mips_opts.micromips);
            case 'b':           /* Base register.  */
            case 'b':           /* Base register.  */
            case 'd':           /* Destination register.  */
            case 'd':           /* Destination register.  */
            case 's':           /* Source register.  */
            case 's':           /* Source register.  */
            case 't':           /* Target register.  */
            case 't':           /* Target register.  */
            case 'r':           /* Both target and source.  */
            case 'r':           /* Both target and source.  */
            case 'v':           /* Both dest and source.  */
            case 'v':           /* Both dest and source.  */
            case 'w':           /* Both dest and target.  */
            case 'w':           /* Both dest and target.  */
            case 'E':           /* Coprocessor target register.  */
            case 'E':           /* Coprocessor target register.  */
            case 'K':           /* RDHWR destination register.  */
            case 'K':           /* RDHWR destination register.  */
            case 'x':           /* Ignore register name.  */
 
            case 'z':           /* Must be zero register.  */
            case 'z':           /* Must be zero register.  */
            case 'U':           /* Destination register (CLO/CLZ).  */
            do_reg:
            case 'g':           /* Coprocessor destination register.  */
 
              s_reset = s;
              s_reset = s;
              if (*args == 'E' || *args == 'K')
              if (*args == 'E' || *args == 'K')
                ok = reg_lookup (&s, RTYPE_NUM, &regno);
                ok = reg_lookup (&s, RTYPE_NUM, &regno);
              else
              else
                {
                {
Line 9835... Line 11753...
                    {
                    {
                    case 'r':
                    case 'r':
                    case 's':
                    case 's':
                    case 'v':
                    case 'v':
                    case 'b':
                    case 'b':
                      INSERT_OPERAND (RS, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, RS, *ip, regno);
                      break;
                      break;
                    case 'd':
 
                    case 'K':
                    case 'K':
 
                      if (mips_opts.micromips)
 
                        INSERT_OPERAND (1, RS, *ip, regno);
 
                      else
 
                        INSERT_OPERAND (0, RD, *ip, regno);
 
                      break;
 
 
 
                    case 'd':
                    case 'g':
                    case 'g':
                      INSERT_OPERAND (RD, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, RD, *ip, regno);
                      break;
                      break;
 
 
                    case 'U':
                    case 'U':
                      INSERT_OPERAND (RD, *ip, regno);
                      gas_assert (!mips_opts.micromips);
                      INSERT_OPERAND (RT, *ip, regno);
                      INSERT_OPERAND (0, RD, *ip, regno);
 
                      INSERT_OPERAND (0, RT, *ip, regno);
                      break;
                      break;
 
 
                    case 'w':
                    case 'w':
                    case 't':
                    case 't':
                    case 'E':
                    case 'E':
                      INSERT_OPERAND (RT, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, RT, *ip, regno);
 
                      break;
 
 
 
                    case 'y':
 
                      gas_assert (mips_opts.micromips);
 
                      INSERT_OPERAND (1, RS3, *ip, regno);
                      break;
                      break;
 
 
                    case 'x':
                    case 'x':
                      /* This case exists because on the r3000 trunc
                      /* This case exists because on the r3000 trunc
                         expands into a macro which requires a gp
                         expands into a macro which requires a gp
                         register.  On the r6000 or r4000 it is
                         register.  On the r6000 or r4000 it is
                         assembled into a single instruction which
                         assembled into a single instruction which
                         ignores the register.  Thus the insn version
                         ignores the register.  Thus the insn version
                         is MIPS_ISA2 and uses 'x', and the macro
                         is MIPS_ISA2 and uses 'x', and the macro
                         version is MIPS_ISA1 and uses 't'.  */
                         version is MIPS_ISA1 and uses 't'.  */
                      break;
                      break;
 
 
                    case 'z':
                    case 'z':
                      /* This case is for the div instruction, which
                      /* This case is for the div instruction, which
                         acts differently if the destination argument
                         acts differently if the destination argument
                         is $0.  This only matches $0, and is checked
                         is $0.  This only matches $0, and is checked
                         outside the switch.  */
                         outside the switch.  */
Line 9874... Line 11809...
                }
                }
              switch (*args++)
              switch (*args++)
                {
                {
                case 'r':
                case 'r':
                case 'v':
                case 'v':
                  INSERT_OPERAND (RS, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, RS, *ip, lastregno);
                  continue;
                  continue;
 
 
                case 'w':
                case 'w':
                  INSERT_OPERAND (RT, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, RT, *ip, lastregno);
                  continue;
                  continue;
                }
                }
              break;
              break;
 
 
            case 'O':           /* MDMX alignment immediate constant.  */
            case 'O':           /* MDMX alignment immediate constant.  */
 
              gas_assert (!mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
              if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
                as_warn (_("Improper align amount (%ld), using low bits"),
                as_warn (_("Improper align amount (%ld), using low bits"),
                         (long) imm_expr.X_add_number);
                         (long) imm_expr.X_add_number);
              INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
              INSERT_OPERAND (0, ALN, *ip, imm_expr.X_add_number);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case 'Q':           /* MDMX vector, element sel, or const.  */
            case 'Q':           /* MDMX vector, element sel, or const.  */
              if (s[0] != '$')
              if (s[0] != '$')
                {
                {
                  /* MDMX Immediate.  */
                  /* MDMX Immediate.  */
 
                  gas_assert (!mips_opts.micromips);
                  my_getExpression (&imm_expr, s);
                  my_getExpression (&imm_expr, s);
                  check_absolute_expr (ip, &imm_expr);
                  check_absolute_expr (ip, &imm_expr);
                  if ((unsigned long) imm_expr.X_add_number > OP_MASK_FT)
                  if ((unsigned long) imm_expr.X_add_number > OP_MASK_FT)
                    as_warn (_("Invalid MDMX Immediate (%ld)"),
                    as_warn (_("Invalid MDMX Immediate (%ld)"),
                             (long) imm_expr.X_add_number);
                             (long) imm_expr.X_add_number);
                  INSERT_OPERAND (FT, *ip, imm_expr.X_add_number);
                  INSERT_OPERAND (0, FT, *ip, imm_expr.X_add_number);
                  if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
                  if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
                    ip->insn_opcode |= MDMX_FMTSEL_IMM_QH << OP_SH_VSEL;
                    ip->insn_opcode |= MDMX_FMTSEL_IMM_QH << OP_SH_VSEL;
                  else
                  else
                    ip->insn_opcode |= MDMX_FMTSEL_IMM_OB << OP_SH_VSEL;
                    ip->insn_opcode |= MDMX_FMTSEL_IMM_OB << OP_SH_VSEL;
                  imm_expr.X_op = O_absent;
                  imm_expr.X_op = O_absent;
Line 9916... Line 11854...
              /* Not MDMX Immediate.  Fall through.  */
              /* Not MDMX Immediate.  Fall through.  */
            case 'X':           /* MDMX destination register.  */
            case 'X':           /* MDMX destination register.  */
            case 'Y':           /* MDMX source register.  */
            case 'Y':           /* MDMX source register.  */
            case 'Z':           /* MDMX target register.  */
            case 'Z':           /* MDMX target register.  */
              is_mdmx = 1;
              is_mdmx = 1;
 
            case 'W':
 
              gas_assert (!mips_opts.micromips);
            case 'D':           /* Floating point destination register.  */
            case 'D':           /* Floating point destination register.  */
            case 'S':           /* Floating point source register.  */
            case 'S':           /* Floating point source register.  */
            case 'T':           /* Floating point target register.  */
            case 'T':           /* Floating point target register.  */
            case 'R':           /* Floating point source register.  */
            case 'R':           /* Floating point source register.  */
            case 'V':
            case 'V':
            case 'W':
 
              rtype = RTYPE_FPU;
              rtype = RTYPE_FPU;
              if (is_mdmx
              if (is_mdmx
                  || (mips_opts.ase_mdmx
                  || (mips_opts.ase_mdmx
                      && (ip->insn_mo->pinfo & FP_D)
                      && (ip->insn_mo->pinfo & FP_D)
                      && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY
                      && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY
Line 9957... Line 11896...
                    }
                    }
                  switch (c)
                  switch (c)
                    {
                    {
                    case 'D':
                    case 'D':
                    case 'X':
                    case 'X':
                      INSERT_OPERAND (FD, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, FD, *ip, regno);
                      break;
                      break;
 
 
                    case 'V':
                    case 'V':
                    case 'S':
                    case 'S':
                    case 'Y':
                    case 'Y':
                      INSERT_OPERAND (FS, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, FS, *ip, regno);
                      break;
                      break;
 
 
                    case 'Q':
                    case 'Q':
                      /* This is like 'Z', but also needs to fix the MDMX
                      /* This is like 'Z', but also needs to fix the MDMX
                         vector/scalar select bits.  Note that the
                         vector/scalar select bits.  Note that the
                         scalar immediate case is handled above.  */
                         scalar immediate case is handled above.  */
                      if (*s == '[')
                      if (*s == '[')
Line 10002... Line 11943...
                        }
                        }
                      /* Fall through.  */
                      /* Fall through.  */
                    case 'W':
                    case 'W':
                    case 'T':
                    case 'T':
                    case 'Z':
                    case 'Z':
                      INSERT_OPERAND (FT, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, FT, *ip, regno);
                      break;
                      break;
 
 
                    case 'R':
                    case 'R':
                      INSERT_OPERAND (FR, *ip, regno);
                      INSERT_OPERAND (mips_opts.micromips, FR, *ip, regno);
                      break;
                      break;
                    }
                    }
                  lastregno = regno;
                  lastregno = regno;
                  continue;
                  continue;
                }
                }
 
 
              switch (*args++)
              switch (*args++)
                {
                {
                case 'V':
                case 'V':
                  INSERT_OPERAND (FS, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, FS, *ip, lastregno);
                  continue;
                  continue;
 
 
                case 'W':
                case 'W':
                  INSERT_OPERAND (FT, *ip, lastregno);
                  INSERT_OPERAND (mips_opts.micromips, FT, *ip, lastregno);
                  continue;
                  continue;
                }
                }
              break;
              break;
 
 
            case 'I':
            case 'I':
Line 10237... Line 12180...
              if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
              if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
                {
                {
                  int more;
                  int more;
                  offsetT minval, maxval;
                  offsetT minval, maxval;
 
 
                  more = (insn + 1 < &mips_opcodes[NUMOPCODES]
                  more = (insn + 1 < past
                          && strcmp (insn->name, insn[1].name) == 0);
                          && strcmp (insn->name, insn[1].name) == 0);
 
 
                  /* If the expression was written as an unsigned number,
                  /* If the expression was written as an unsigned number,
                     only treat it as signed if there are no more
                     only treat it as signed if there are no more
                     alternatives.  */
                     alternatives.  */
Line 10320... Line 12263...
                        (unsigned long) imm_expr.X_add_number);
                        (unsigned long) imm_expr.X_add_number);
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            case 'a':           /* 26-bit address.  */
            case 'a':           /* 26-bit address.  */
 
              *offset_reloc = BFD_RELOC_MIPS_JMP;
              my_getExpression (&offset_expr, s);
              my_getExpression (&offset_expr, s);
              s = expr_end;
              s = expr_end;
              *offset_reloc = BFD_RELOC_MIPS_JMP;
 
              continue;
              continue;
 
 
            case 'N':           /* 3-bit branch condition code.  */
            case 'N':           /* 3-bit branch condition code.  */
            case 'M':           /* 3-bit compare condition code.  */
            case 'M':           /* 3-bit compare condition code.  */
              rtype = RTYPE_CCC;
              rtype = RTYPE_CCC;
              if (ip->insn_mo->pinfo & (FP_D | FP_S))
              if (ip->insn_mo->pinfo & (FP_D | FP_S))
                rtype |= RTYPE_FCC;
                rtype |= RTYPE_FCC;
              if (!reg_lookup (&s, rtype, &regno))
              if (!reg_lookup (&s, rtype, &regno))
 
                break;
 
              if ((strcmp (str + strlen (str) - 3, ".ps") == 0
 
                   || strcmp (str + strlen (str) - 5, "any2f") == 0
 
                   || strcmp (str + strlen (str) - 5, "any2t") == 0)
 
                  && (regno & 1) != 0)
 
                as_warn (_("Condition code register should be even for %s, "
 
                           "was %d"),
 
                         str, regno);
 
              if ((strcmp (str + strlen (str) - 5, "any4f") == 0
 
                   || strcmp (str + strlen (str) - 5, "any4t") == 0)
 
                  && (regno & 3) != 0)
 
                as_warn (_("Condition code register should be 0 or 4 for %s, "
 
                           "was %d"),
 
                         str, regno);
 
              if (*args == 'N')
 
                INSERT_OPERAND (mips_opts.micromips, BCC, *ip, regno);
 
              else
 
                INSERT_OPERAND (mips_opts.micromips, CCC, *ip, regno);
 
              continue;
 
 
 
            case 'H':
 
              if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
 
                s += 2;
 
              if (ISDIGIT (*s))
 
                {
 
                  c = 0;
 
                  do
 
                    {
 
                      c *= 10;
 
                      c += *s - '0';
 
                      ++s;
 
                    }
 
                  while (ISDIGIT (*s));
 
                }
 
              else
 
                c = 8; /* Invalid sel value.  */
 
 
 
              if (c > 7)
 
                as_bad (_("Invalid coprocessor sub-selection value (0-7)"));
 
              INSERT_OPERAND (mips_opts.micromips, SEL, *ip, c);
 
              continue;
 
 
 
            case 'e':
 
              gas_assert (!mips_opts.micromips);
 
              /* Must be at least one digit.  */
 
              my_getExpression (&imm_expr, s);
 
              check_absolute_expr (ip, &imm_expr);
 
 
 
              if ((unsigned long) imm_expr.X_add_number
 
                  > (unsigned long) OP_MASK_VECBYTE)
 
                {
 
                  as_bad (_("bad byte vector index (%ld)"),
 
                           (long) imm_expr.X_add_number);
 
                  imm_expr.X_add_number = 0;
 
                }
 
 
 
              INSERT_OPERAND (0, VECBYTE, *ip, imm_expr.X_add_number);
 
              imm_expr.X_op = O_absent;
 
              s = expr_end;
 
              continue;
 
 
 
            case '%':
 
              gas_assert (!mips_opts.micromips);
 
              my_getExpression (&imm_expr, s);
 
              check_absolute_expr (ip, &imm_expr);
 
 
 
              if ((unsigned long) imm_expr.X_add_number
 
                  > (unsigned long) OP_MASK_VECALIGN)
 
                {
 
                  as_bad (_("bad byte vector index (%ld)"),
 
                           (long) imm_expr.X_add_number);
 
                  imm_expr.X_add_number = 0;
 
                }
 
 
 
              INSERT_OPERAND (0, VECALIGN, *ip, imm_expr.X_add_number);
 
              imm_expr.X_op = O_absent;
 
              s = expr_end;
 
              continue;
 
 
 
            case 'm':           /* Opcode extension character.  */
 
              gas_assert (mips_opts.micromips);
 
              c = *++args;
 
              switch (c)
 
                {
 
                case 'r':
 
                  if (strncmp (s, "$pc", 3) == 0)
 
                    {
 
                      s += 3;
 
                      continue;
 
                    }
 
                  break;
 
 
 
                case 'a':
 
                case 'b':
 
                case 'c':
 
                case 'd':
 
                case 'e':
 
                case 'f':
 
                case 'g':
 
                case 'h':
 
                case 'i':
 
                case 'j':
 
                case 'l':
 
                case 'm':
 
                case 'n':
 
                case 'p':
 
                case 'q':
 
                case 's':
 
                case 't':
 
                case 'x':
 
                case 'y':
 
                case 'z':
 
                  s_reset = s;
 
                  ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
 
                  if (regno == AT && mips_opts.at)
 
                    {
 
                      if (mips_opts.at == ATREG)
 
                        as_warn (_("Used $at without \".set noat\""));
 
                      else
 
                        as_warn (_("Used $%u with \".set at=$%u\""),
 
                                 regno, mips_opts.at);
 
                    }
 
                  if (!ok)
 
                    {
 
                      if (c == 'c')
 
                        {
 
                          gas_assert (args[1] == ',');
 
                          regno = lastregno;
 
                          ++args;
 
                        }
 
                      else if (c == 't')
 
                        {
 
                          gas_assert (args[1] == ',');
 
                          ++args;
 
                          continue;                     /* Nothing to do.  */
 
                        }
 
                      else
 
                        break;
 
                    }
 
 
 
                  if (c == 'j' && !strncmp (ip->insn_mo->name, "jalr", 4))
 
                    {
 
                      if (regno == lastregno)
 
                        {
 
                          insn_error
 
                            = _("Source and destination must be different");
 
                          continue;
 
                        }
 
                      if (regno == 31 && lastregno == 0xffffffff)
 
                        {
 
                          insn_error
 
                            = _("A destination register must be supplied");
 
                          continue;
 
                        }
 
                    }
 
 
 
                  if (*s == ' ')
 
                    ++s;
 
                  if (args[1] != *s)
 
                    {
 
                      if (c == 'e')
 
                        {
 
                          gas_assert (args[1] == ',');
 
                          regno = lastregno;
 
                          s = s_reset;
 
                          ++args;
 
                        }
 
                      else if (c == 't')
 
                        {
 
                          gas_assert (args[1] == ',');
 
                          s = s_reset;
 
                          ++args;
 
                          continue;                     /* Nothing to do.  */
 
                        }
 
                    }
 
 
 
                  /* Make sure regno is the same as lastregno.  */
 
                  if (c == 't' && regno != lastregno)
 
                    break;
 
 
 
                  /* Make sure regno is the same as destregno.  */
 
                  if (c == 'x' && regno != destregno)
 
                    break;
 
 
 
                  /* We need to save regno, before regno maps to the
 
                     microMIPS register encoding.  */
 
                  lastregno = regno;
 
 
 
                  if (c == 'f')
 
                    destregno = regno;
 
 
 
                  switch (c)
 
                    {
 
                      case 'a':
 
                        if (regno != GP)
 
                          regno = ILLEGAL_REG;
 
                        break;
 
 
 
                      case 'b':
 
                        regno = mips32_to_micromips_reg_b_map[regno];
 
                        break;
 
 
 
                      case 'c':
 
                        regno = mips32_to_micromips_reg_c_map[regno];
 
                        break;
 
 
 
                      case 'd':
 
                        regno = mips32_to_micromips_reg_d_map[regno];
 
                        break;
 
 
 
                      case 'e':
 
                        regno = mips32_to_micromips_reg_e_map[regno];
 
                        break;
 
 
 
                      case 'f':
 
                        regno = mips32_to_micromips_reg_f_map[regno];
 
                        break;
 
 
 
                      case 'g':
 
                        regno = mips32_to_micromips_reg_g_map[regno];
 
                        break;
 
 
 
                      case 'h':
 
                        regno = mips32_to_micromips_reg_h_map[regno];
 
                        break;
 
 
 
                      case 'i':
 
                        switch (EXTRACT_OPERAND (1, MI, *ip))
 
                          {
 
                            case 4:
 
                              if (regno == 21)
 
                                regno = 3;
 
                              else if (regno == 22)
 
                                regno = 4;
 
                              else if (regno == 5)
 
                                regno = 5;
 
                              else if (regno == 6)
 
                                regno = 6;
 
                              else if (regno == 7)
 
                                regno = 7;
 
                              else
 
                                regno = ILLEGAL_REG;
 
                              break;
 
 
 
                            case 5:
 
                              if (regno == 6)
 
                                regno = 0;
 
                              else if (regno == 7)
 
                                regno = 1;
 
                              else
 
                                regno = ILLEGAL_REG;
 
                              break;
 
 
 
                            case 6:
 
                              if (regno == 7)
 
                                regno = 2;
 
                              else
 
                                regno = ILLEGAL_REG;
 
                              break;
 
 
 
                            default:
 
                              regno = ILLEGAL_REG;
 
                              break;
 
                          }
 
                        break;
 
 
 
                      case 'l':
 
                        regno = mips32_to_micromips_reg_l_map[regno];
 
                        break;
 
 
 
                      case 'm':
 
                        regno = mips32_to_micromips_reg_m_map[regno];
 
                        break;
 
 
 
                      case 'n':
 
                        regno = mips32_to_micromips_reg_n_map[regno];
 
                        break;
 
 
 
                      case 'q':
 
                        regno = mips32_to_micromips_reg_q_map[regno];
 
                        break;
 
 
 
                      case 's':
 
                        if (regno != SP)
 
                          regno = ILLEGAL_REG;
 
                        break;
 
 
 
                      case 'y':
 
                        if (regno != 31)
 
                          regno = ILLEGAL_REG;
 
                        break;
 
 
 
                      case 'z':
 
                        if (regno != ZERO)
 
                          regno = ILLEGAL_REG;
 
                        break;
 
 
 
                      case 'j': /* Do nothing.  */
 
                      case 'p':
 
                      case 't':
 
                      case 'x':
 
                        break;
 
 
 
                      default:
 
                        internalError ();
 
                    }
 
 
 
                  if (regno == ILLEGAL_REG)
 
                    break;
 
 
 
                  switch (c)
 
                    {
 
                      case 'b':
 
                        INSERT_OPERAND (1, MB, *ip, regno);
 
                        break;
 
 
 
                      case 'c':
 
                        INSERT_OPERAND (1, MC, *ip, regno);
 
                        break;
 
 
 
                      case 'd':
 
                        INSERT_OPERAND (1, MD, *ip, regno);
 
                        break;
 
 
 
                      case 'e':
 
                        INSERT_OPERAND (1, ME, *ip, regno);
 
                        break;
 
 
 
                      case 'f':
 
                        INSERT_OPERAND (1, MF, *ip, regno);
 
                        break;
 
 
 
                      case 'g':
 
                        INSERT_OPERAND (1, MG, *ip, regno);
 
                        break;
 
 
 
                      case 'h':
 
                        INSERT_OPERAND (1, MH, *ip, regno);
 
                        break;
 
 
 
                      case 'i':
 
                        INSERT_OPERAND (1, MI, *ip, regno);
 
                        break;
 
 
 
                      case 'j':
 
                        INSERT_OPERAND (1, MJ, *ip, regno);
 
                        break;
 
 
 
                      case 'l':
 
                        INSERT_OPERAND (1, ML, *ip, regno);
 
                        break;
 
 
 
                      case 'm':
 
                        INSERT_OPERAND (1, MM, *ip, regno);
 
                        break;
 
 
 
                      case 'n':
 
                        INSERT_OPERAND (1, MN, *ip, regno);
 
                        break;
 
 
 
                      case 'p':
 
                        INSERT_OPERAND (1, MP, *ip, regno);
 
                        break;
 
 
 
                      case 'q':
 
                        INSERT_OPERAND (1, MQ, *ip, regno);
 
                        break;
 
 
 
                      case 'a': /* Do nothing.  */
 
                      case 's': /* Do nothing.  */
 
                      case 't': /* Do nothing.  */
 
                      case 'x': /* Do nothing.  */
 
                      case 'y': /* Do nothing.  */
 
                      case 'z': /* Do nothing.  */
 
                        break;
 
 
 
                      default:
 
                        internalError ();
 
                    }
 
                  continue;
 
 
 
                case 'A':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    /* Check whether there is only a single bracketed
 
                       expression left.  If so, it must be the base register
 
                       and the constant must be zero.  */
 
                    if (*s == '(' && strchr (s + 1, '(') == 0)
 
                      {
 
                        INSERT_OPERAND (1, IMMA, *ip, 0);
 
                        continue;
 
                      }
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, -64, 64, 2))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 2;
 
                    INSERT_OPERAND (1, IMMA, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'B':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || ep.X_op != O_constant)
 
                      break;
 
 
 
                    for (imm = 0; imm < 8; imm++)
 
                      if (micromips_imm_b_map[imm] == ep.X_add_number)
 
                        break;
 
                    if (imm >= 8)
 
                      break;
 
 
 
                    INSERT_OPERAND (1, IMMB, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'C':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || ep.X_op != O_constant)
 
                      break;
 
 
 
                    for (imm = 0; imm < 16; imm++)
 
                      if (micromips_imm_c_map[imm] == ep.X_add_number)
 
                        break;
 
                    if (imm >= 16)
 
                      break;
 
 
 
                    INSERT_OPERAND (1, IMMC, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'D':       /* pc relative offset */
 
                case 'E':       /* pc relative offset */
 
                  my_getExpression (&offset_expr, s);
 
                  if (offset_expr.X_op == O_register)
 
                    break;
 
 
 
                  if (!forced_insn_length)
 
                    *offset_reloc = (int) BFD_RELOC_UNUSED + c;
 
                  else if (c == 'D')
 
                    *offset_reloc = BFD_RELOC_MICROMIPS_10_PCREL_S1;
 
                  else
 
                    *offset_reloc = BFD_RELOC_MICROMIPS_7_PCREL_S1;
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'F':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 16, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number;
 
                    INSERT_OPERAND (1, IMMF, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'G':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    /* Check whether there is only a single bracketed
 
                       expression left.  If so, it must be the base register
 
                       and the constant must be zero.  */
 
                    if (*s == '(' && strchr (s + 1, '(') == 0)
 
                      {
 
                        INSERT_OPERAND (1, IMMG, *ip, 0);
 
                        continue;
 
                      }
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, -1, 15, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number & 15;
 
                    INSERT_OPERAND (1, IMMG, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'H':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    /* Check whether there is only a single bracketed
 
                       expression left.  If so, it must be the base register
 
                       and the constant must be zero.  */
 
                    if (*s == '(' && strchr (s + 1, '(') == 0)
 
                      {
 
                        INSERT_OPERAND (1, IMMH, *ip, 0);
 
                        continue;
 
                      }
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 16, 1))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 1;
 
                    INSERT_OPERAND (1, IMMH, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'I':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, -1, 127, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number & 127;
 
                    INSERT_OPERAND (1, IMMI, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'J':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    /* Check whether there is only a single bracketed
 
                       expression left.  If so, it must be the base register
 
                       and the constant must be zero.  */
 
                    if (*s == '(' && strchr (s + 1, '(') == 0)
 
                      {
 
                        INSERT_OPERAND (1, IMMJ, *ip, 0);
 
                        continue;
 
                      }
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 16, 2))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 2;
 
                    INSERT_OPERAND (1, IMMJ, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'L':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    /* Check whether there is only a single bracketed
 
                       expression left.  If so, it must be the base register
 
                       and the constant must be zero.  */
 
                    if (*s == '(' && strchr (s + 1, '(') == 0)
 
                      {
 
                        INSERT_OPERAND (1, IMML, *ip, 0);
 
                        continue;
 
                      }
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 16, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number;
 
                    INSERT_OPERAND (1, IMML, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'M':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 1, 9, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number & 7;
 
                    INSERT_OPERAND (1, IMMM, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'N':       /* Register list for lwm and swm.  */
 
                  {
 
                    /* A comma-separated list of registers and/or
 
                       dash-separated contiguous ranges including
 
                       both ra and a set of one or more registers
 
                       starting at s0 up to s3 which have to be
 
                       consecutive, e.g.:
 
 
 
                       s0, ra
 
                       s0, s1, ra, s2, s3
 
                       s0-s2, ra
 
 
 
                       and any permutations of these.  */
 
                    unsigned int reglist;
 
                    int imm;
 
 
 
                    if (!reglist_lookup (&s, RTYPE_NUM | RTYPE_GP, &reglist))
 
                      break;
 
 
 
                    if ((reglist & 0xfff1ffff) != 0x80010000)
 
                      break;
 
 
 
                    reglist = (reglist >> 17) & 7;
 
                    reglist += 1;
 
                    if ((reglist & -reglist) != reglist)
 
                      break;
 
 
 
                    imm = ffs (reglist) - 1;
 
                    INSERT_OPERAND (1, IMMN, *ip, imm);
 
                  }
 
                  continue;
 
 
 
                case 'O':       /* sdbbp 4-bit code.  */
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 16, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number;
 
                    INSERT_OPERAND (1, IMMO, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'P':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 32, 2))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 2;
 
                    INSERT_OPERAND (1, IMMP, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'Q':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, -0x400000, 0x400000, 2))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 2;
 
                    INSERT_OPERAND (1, IMMQ, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'U':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    /* Check whether there is only a single bracketed
 
                       expression left.  If so, it must be the base register
 
                       and the constant must be zero.  */
 
                    if (*s == '(' && strchr (s + 1, '(') == 0)
 
                      {
 
                        INSERT_OPERAND (1, IMMU, *ip, 0);
 
                        continue;
 
                      }
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 32, 2))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 2;
 
                    INSERT_OPERAND (1, IMMU, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'W':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, 0, 64, 2))
 
                      break;
 
 
 
                    imm = ep.X_add_number >> 2;
 
                    INSERT_OPERAND (1, IMMW, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'X':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || !expr_const_in_range (&ep, -8, 8, 0))
 
                      break;
 
 
 
                    imm = ep.X_add_number;
 
                    INSERT_OPERAND (1, IMMX, *ip, imm);
 
                  }
 
                  s = expr_end;
 
                  continue;
 
 
 
                case 'Y':
 
                  {
 
                    bfd_reloc_code_real_type r[3];
 
                    expressionS ep;
 
                    int imm;
 
 
 
                    if (my_getSmallExpression (&ep, r, s) > 0
 
                        || expr_const_in_range (&ep, -2, 2, 2)
 
                        || !expr_const_in_range (&ep, -258, 258, 2))
                break;
                break;
              if ((strcmp (str + strlen (str) - 3, ".ps") == 0
 
                   || strcmp (str + strlen (str) - 5, "any2f") == 0
                    imm = ep.X_add_number >> 2;
                   || strcmp (str + strlen (str) - 5, "any2t") == 0)
                    imm = ((imm >> 1) & ~0xff) | (imm & 0xff);
                  && (regno & 1) != 0)
                    INSERT_OPERAND (1, IMMY, *ip, imm);
                as_warn (_("Condition code register should be even for %s, "
                  }
                           "was %d"),
                  s = expr_end;
                         str, regno);
 
              if ((strcmp (str + strlen (str) - 5, "any4f") == 0
 
                   || strcmp (str + strlen (str) - 5, "any4t") == 0)
 
                  && (regno & 3) != 0)
 
                as_warn (_("Condition code register should be 0 or 4 for %s, "
 
                           "was %d"),
 
                         str, regno);
 
              if (*args == 'N')
 
                INSERT_OPERAND (BCC, *ip, regno);
 
              else
 
                INSERT_OPERAND (CCC, *ip, regno);
 
              continue;
              continue;
 
 
            case 'H':
                case 'Z':
              if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
 
                s += 2;
 
              if (ISDIGIT (*s))
 
                {
 
                  c = 0;
 
                  do
 
                    {
                    {
                      c *= 10;
                    bfd_reloc_code_real_type r[3];
                      c += *s - '0';
                    expressionS ep;
                      ++s;
 
                    }
 
                  while (ISDIGIT (*s));
 
                }
 
              else
 
                c = 8; /* Invalid sel value.  */
 
 
 
              if (c > 7)
                    if (my_getSmallExpression (&ep, r, s) > 0
                as_bad (_("Invalid coprocessor sub-selection value (0-7)"));
                        || !expr_const_in_range (&ep, 0, 1, 0))
              ip->insn_opcode |= c;
                      break;
 
                  }
 
                  s = expr_end;
              continue;
              continue;
 
 
            case 'e':
                default:
              /* Must be at least one digit.  */
                  as_bad (_("Internal error: bad microMIPS opcode "
              my_getExpression (&imm_expr, s);
                            "(unknown extension operand type `m%c'): %s %s"),
              check_absolute_expr (ip, &imm_expr);
                          *args, insn->name, insn->args);
 
                  /* Further processing is fruitless.  */
 
                  return;
 
                }
 
              break;
 
 
              if ((unsigned long) imm_expr.X_add_number
            case 'n':           /* Register list for 32-bit lwm and swm.  */
                  > (unsigned long) OP_MASK_VECBYTE)
              gas_assert (mips_opts.micromips);
                {
                {
                  as_bad (_("bad byte vector index (%ld)"),
                /* A comma-separated list of registers and/or
                           (long) imm_expr.X_add_number);
                   dash-separated contiguous ranges including
                  imm_expr.X_add_number = 0;
                   at least one of ra and a set of one or more
                }
                   registers starting at s0 up to s7 and then
 
                   s8 which have to be consecutive, e.g.:
 
 
 
                   ra
 
                   s0
 
                   ra, s0, s1, s2
 
                   s0-s8
 
                   s0-s5, ra
 
 
 
                   and any permutations of these.  */
 
                unsigned int reglist;
 
                int imm;
 
                int ra;
 
 
              INSERT_OPERAND (VECBYTE, *ip, imm_expr.X_add_number);
                if (!reglist_lookup (&s, RTYPE_NUM | RTYPE_GP, &reglist))
 
                  break;
 
 
 
                if ((reglist & 0x3f00ffff) != 0)
 
                  break;
 
 
 
                ra = (reglist >> 27) & 0x10;
 
                reglist = ((reglist >> 22) & 0x100) | ((reglist >> 16) & 0xff);
 
                reglist += 1;
 
                if ((reglist & -reglist) != reglist)
 
                  break;
 
 
 
                imm = (ffs (reglist) - 1) | ra;
 
                INSERT_OPERAND (1, RT, *ip, imm);
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              }
              continue;
              continue;
 
 
            case '%':
            case '|':           /* 4-bit trap code.  */
 
              gas_assert (mips_opts.micromips);
              my_getExpression (&imm_expr, s);
              my_getExpression (&imm_expr, s);
              check_absolute_expr (ip, &imm_expr);
              check_absolute_expr (ip, &imm_expr);
 
 
              if ((unsigned long) imm_expr.X_add_number
              if ((unsigned long) imm_expr.X_add_number
                  > (unsigned long) OP_MASK_VECALIGN)
                  > MICROMIPSOP_MASK_TRAP)
                {
                as_bad (_("Trap code (%lu) for %s not in 0..15 range"),
                  as_bad (_("bad byte vector index (%ld)"),
                        (unsigned long) imm_expr.X_add_number,
                           (long) imm_expr.X_add_number);
                        ip->insn_mo->name);
                  imm_expr.X_add_number = 0;
              INSERT_OPERAND (1, TRAP, *ip, imm_expr.X_add_number);
                }
 
 
 
              INSERT_OPERAND (VECALIGN, *ip, imm_expr.X_add_number);
 
              imm_expr.X_op = O_absent;
              imm_expr.X_op = O_absent;
              s = expr_end;
              s = expr_end;
              continue;
              continue;
 
 
            default:
            default:
Line 10415... Line 13120...
              internalError ();
              internalError ();
            }
            }
          break;
          break;
        }
        }
      /* Args don't match.  */
      /* Args don't match.  */
      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
 
          !strcmp (insn->name, insn[1].name))
 
        {
 
          ++insn;
 
          s = argsStart;
          s = argsStart;
          insn_error = _("Illegal operands");
          insn_error = _("Illegal operands");
 
      if (insn + 1 < past && !strcmp (insn->name, insn[1].name))
 
        {
 
          ++insn;
 
          continue;
 
        }
 
      else if (wrong_delay_slot_insns && need_delay_slot_ok)
 
        {
 
          gas_assert (firstinsn);
 
          need_delay_slot_ok = FALSE;
 
          past = insn + 1;
 
          insn = firstinsn;
          continue;
          continue;
        }
        }
      if (save_c)
 
        *(--argsStart) = save_c;
 
      insn_error = _("Illegal operands");
 
      return;
      return;
    }
    }
}
}
 
 
#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
 
 
/* This routine assembles an instruction into its binary format when
/* This routine assembles an instruction into its binary format when
   assembling for the mips16.  As a side effect, it sets one of the
   assembling for the mips16.  As a side effect, it sets one of the
   global variables imm_reloc or offset_reloc to the type of
   global variables imm_reloc or offset_reloc to the type of relocation
   relocation to do if one of the operands is an address expression.
   to do if one of the operands is an address expression.  It also sets
   It also sets mips16_small and mips16_ext if the user explicitly
   forced_insn_length to the resulting instruction size in bytes if the
   requested a small or extended instruction.  */
   user explicitly requested a small or extended instruction.  */
 
 
static void
static void
mips16_ip (char *str, struct mips_cl_insn *ip)
mips16_ip (char *str, struct mips_cl_insn *ip)
{
{
  char *s;
  char *s;
Line 10453... Line 13162...
  char *s_reset;
  char *s_reset;
  size_t i;
  size_t i;
 
 
  insn_error = NULL;
  insn_error = NULL;
 
 
  mips16_small = FALSE;
  forced_insn_length = 0;
  mips16_ext = FALSE;
 
 
 
  for (s = str; ISLOWER (*s); ++s)
  for (s = str; ISLOWER (*s); ++s)
    ;
    ;
  switch (*s)
  switch (*s)
    {
    {
Line 10471... Line 13179...
 
 
    case '.':
    case '.':
      if (s[1] == 't' && s[2] == ' ')
      if (s[1] == 't' && s[2] == ' ')
        {
        {
          *s = '\0';
          *s = '\0';
          mips16_small = TRUE;
          forced_insn_length = 2;
          s += 3;
          s += 3;
          break;
          break;
        }
        }
      else if (s[1] == 'e' && s[2] == ' ')
      else if (s[1] == 'e' && s[2] == ' ')
        {
        {
          *s = '\0';
          *s = '\0';
          mips16_ext = TRUE;
          forced_insn_length = 4;
          s += 3;
          s += 3;
          break;
          break;
        }
        }
      /* Fall through.  */
      /* Fall through.  */
    default:
    default:
      insn_error = _("unknown opcode");
      insn_error = _("unknown opcode");
      return;
      return;
    }
    }
 
 
  if (mips_opts.noautoextend && ! mips16_ext)
  if (mips_opts.noautoextend && !forced_insn_length)
    mips16_small = TRUE;
    forced_insn_length = 2;
 
 
  if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
  if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
    {
    {
      insn_error = _("unrecognized opcode");
      insn_error = _("unrecognized opcode");
      return;
      return;
Line 10589... Line 13297...
                            internalError ();
                            internalError ();
                        }
                        }
                      *offset_reloc = BFD_RELOC_UNUSED;
                      *offset_reloc = BFD_RELOC_UNUSED;
 
 
                      mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
                      mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
                                    tmp, TRUE, mips16_small,
                                    tmp, TRUE, forced_insn_length == 2,
                                    mips16_ext, &ip->insn_opcode,
                                    forced_insn_length == 4, &ip->insn_opcode,
                                    &ip->use_extend, &ip->extend);
                                    &ip->use_extend, &ip->extend);
                      imm_expr.X_op = O_absent;
                      imm_expr.X_op = O_absent;
                      *imm_reloc = BFD_RELOC_UNUSED;
                      *imm_reloc = BFD_RELOC_UNUSED;
                    }
                    }
 
 
Line 10770... Line 13478...
              i = my_getSmallExpression (&imm_expr, imm_reloc, s);
              i = my_getSmallExpression (&imm_expr, imm_reloc, s);
              if (i > 0)
              if (i > 0)
                {
                {
                  if (imm_expr.X_op != O_constant)
                  if (imm_expr.X_op != O_constant)
                    {
                    {
                      mips16_ext = TRUE;
                      forced_insn_length = 4;
                      ip->use_extend = TRUE;
                      ip->use_extend = TRUE;
                      ip->extend = 0;
                      ip->extend = 0;
                    }
                    }
                  else
                  else
                    {
                    {
Line 11514... Line 14222...
    OPTION_NO_MT,
    OPTION_NO_MT,
    OPTION_SMARTMIPS,
    OPTION_SMARTMIPS,
    OPTION_NO_SMARTMIPS,
    OPTION_NO_SMARTMIPS,
    OPTION_DSPR2,
    OPTION_DSPR2,
    OPTION_NO_DSPR2,
    OPTION_NO_DSPR2,
 
    OPTION_MICROMIPS,
 
    OPTION_NO_MICROMIPS,
 
    OPTION_MCU,
 
    OPTION_NO_MCU,
    OPTION_COMPAT_ARCH_BASE,
    OPTION_COMPAT_ARCH_BASE,
    OPTION_M4650,
    OPTION_M4650,
    OPTION_NO_M4650,
    OPTION_NO_M4650,
    OPTION_M4010,
    OPTION_M4010,
    OPTION_NO_M4010,
    OPTION_NO_M4010,
Line 11606... Line 14318...
  {"mno-mt", no_argument, NULL, OPTION_NO_MT},
  {"mno-mt", no_argument, NULL, OPTION_NO_MT},
  {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
  {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
  {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
  {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
  {"mdspr2", no_argument, NULL, OPTION_DSPR2},
  {"mdspr2", no_argument, NULL, OPTION_DSPR2},
  {"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
  {"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
 
  {"mmicromips", no_argument, NULL, OPTION_MICROMIPS},
 
  {"mno-micromips", no_argument, NULL, OPTION_NO_MICROMIPS},
 
  {"mmcu", no_argument, NULL, OPTION_MCU},
 
  {"mno-mcu", no_argument, NULL, OPTION_NO_MCU},
 
 
  /* Old-style architecture options.  Don't add more of these.  */
  /* Old-style architecture options.  Don't add more of these.  */
  {"m4650", no_argument, NULL, OPTION_M4650},
  {"m4650", no_argument, NULL, OPTION_M4650},
  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
  {"m4010", no_argument, NULL, OPTION_M4010},
  {"m4010", no_argument, NULL, OPTION_M4010},
Line 11860... Line 14576...
 
 
    case OPTION_NO_MT:
    case OPTION_NO_MT:
      mips_opts.ase_mt = 0;
      mips_opts.ase_mt = 0;
      break;
      break;
 
 
 
    case OPTION_MCU:
 
      mips_opts.ase_mcu = 1;
 
      break;
 
 
 
    case OPTION_NO_MCU:
 
      mips_opts.ase_mcu = 0;
 
      break;
 
 
 
    case OPTION_MICROMIPS:
 
      if (mips_opts.mips16 == 1)
 
        {
 
          as_bad (_("-mmicromips cannot be used with -mips16"));
 
          return 0;
 
        }
 
      mips_opts.micromips = 1;
 
      mips_no_prev_insn ();
 
      break;
 
 
 
    case OPTION_NO_MICROMIPS:
 
      mips_opts.micromips = 0;
 
      mips_no_prev_insn ();
 
      break;
 
 
    case OPTION_MIPS16:
    case OPTION_MIPS16:
 
      if (mips_opts.micromips == 1)
 
        {
 
          as_bad (_("-mips16 cannot be used with -micromips"));
 
          return 0;
 
        }
      mips_opts.mips16 = 1;
      mips_opts.mips16 = 1;
      mips_no_prev_insn ();
      mips_no_prev_insn ();
      break;
      break;
 
 
    case OPTION_NO_MIPS16:
    case OPTION_NO_MIPS16:
Line 12298... Line 15042...
 
 
  /* If the selected architecture includes support for ASEs, enable
  /* If the selected architecture includes support for ASEs, enable
     generation of code for them.  */
     generation of code for them.  */
  if (mips_opts.mips16 == -1)
  if (mips_opts.mips16 == -1)
    mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
    mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
 
  if (mips_opts.micromips == -1)
 
    mips_opts.micromips = (CPU_HAS_MICROMIPS (file_mips_arch)) ? 1 : 0;
  if (mips_opts.ase_mips3d == -1)
  if (mips_opts.ase_mips3d == -1)
    mips_opts.ase_mips3d = ((arch_info->flags & MIPS_CPU_ASE_MIPS3D)
    mips_opts.ase_mips3d = ((arch_info->flags & MIPS_CPU_ASE_MIPS3D)
                            && file_mips_fp32 == 0) ? 1 : 0;
                            && file_mips_fp32 == 0) ? 1 : 0;
  if (mips_opts.ase_mips3d && file_mips_fp32 == 1)
  if (mips_opts.ase_mips3d && file_mips_fp32 == 1)
    as_bad (_("-mfp32 used with -mips3d"));
    as_bad (_("-mfp32 used with -mips3d"));
Line 12337... Line 15083...
    mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
    mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
  if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
  if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
    as_warn (_("%s ISA does not support MT ASE"),
    as_warn (_("%s ISA does not support MT ASE"),
             mips_cpu_info_from_isa (mips_opts.isa)->name);
             mips_cpu_info_from_isa (mips_opts.isa)->name);
 
 
 
  if (mips_opts.ase_mcu == -1)
 
    mips_opts.ase_mcu = (arch_info->flags & MIPS_CPU_ASE_MCU) ? 1 : 0;
 
  if (mips_opts.ase_mcu && !ISA_SUPPORTS_MCU_ASE)
 
      as_warn (_("%s ISA does not support MCU ASE"),
 
               mips_cpu_info_from_isa (mips_opts.isa)->name);
 
 
  file_mips_isa = mips_opts.isa;
  file_mips_isa = mips_opts.isa;
  file_ase_mips3d = mips_opts.ase_mips3d;
  file_ase_mips3d = mips_opts.ase_mips3d;
  file_ase_mdmx = mips_opts.ase_mdmx;
  file_ase_mdmx = mips_opts.ase_mdmx;
  file_ase_smartmips = mips_opts.ase_smartmips;
  file_ase_smartmips = mips_opts.ase_smartmips;
  file_ase_dsp = mips_opts.ase_dsp;
  file_ase_dsp = mips_opts.ase_dsp;
Line 12374... Line 15126...
md_pcrel_from (fixS *fixP)
md_pcrel_from (fixS *fixP)
{
{
  valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
  valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
  switch (fixP->fx_r_type)
  switch (fixP->fx_r_type)
    {
    {
 
    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
 
      /* Return the address of the delay slot.  */
 
      return addr + 2;
 
 
 
    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_JMP:
    case BFD_RELOC_16_PCREL_S2:
    case BFD_RELOC_16_PCREL_S2:
    case BFD_RELOC_MIPS_JMP:
    case BFD_RELOC_MIPS_JMP:
      /* Return the address of the delay slot.  */
      /* Return the address of the delay slot.  */
      return addr + 4;
      return addr + 4;
 
 
    default:
    default:
      /* We have no relocation type for PC relative MIPS16 instructions.  */
      /* We have no relocation type for PC relative MIPS16 instructions.  */
      if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
      if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
        as_bad_where (fixP->fx_file, fixP->fx_line,
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("PC relative MIPS16 instruction references a different section"));
                      _("PC relative MIPS16 instruction references a different section"));
Line 12537... Line 15297...
mips_force_relocation (fixS *fixp)
mips_force_relocation (fixS *fixp)
{
{
  if (generic_force_reloc (fixp))
  if (generic_force_reloc (fixp))
    return 1;
    return 1;
 
 
 
  /* We want to keep BFD_RELOC_MICROMIPS_*_PCREL_S1 relocation,
 
     so that the linker relaxation can update targets.  */
 
  if (fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
 
      || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
 
      || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1)
 
    return 1;
 
 
  if (HAVE_NEWABI
  if (HAVE_NEWABI
      && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
      && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
          || hi16_reloc_p (fixp->fx_r_type)
          || hi16_reloc_p (fixp->fx_r_type)
          || lo16_reloc_p (fixp->fx_r_type)))
          || lo16_reloc_p (fixp->fx_r_type)))
Line 12561... Line 15328...
  /* We ignore generic BFD relocations we don't know about.  */
  /* We ignore generic BFD relocations we don't know about.  */
  howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
  howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
  if (! howto)
  if (! howto)
    return;
    return;
 
 
  gas_assert (fixP->fx_size == 4
  gas_assert (fixP->fx_size == 2
 
              || fixP->fx_size == 4
              || fixP->fx_r_type == BFD_RELOC_16
              || fixP->fx_r_type == BFD_RELOC_16
              || fixP->fx_r_type == BFD_RELOC_64
              || fixP->fx_r_type == BFD_RELOC_64
              || fixP->fx_r_type == BFD_RELOC_CTOR
              || fixP->fx_r_type == BFD_RELOC_CTOR
              || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
              || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
 
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
              || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
              || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
              || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
              || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
              || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
              || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
 
 
  buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
  buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
 
 
  gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
  gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2
 
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
 
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
 
              || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
 
 
  /* Don't treat parts of a composite relocation as done.  There are two
  /* Don't treat parts of a composite relocation as done.  There are two
     reasons for this:
     reasons for this:
 
 
     (1) The second and third parts will be against 0 (RSS_UNDEF) but
     (1) The second and third parts will be against 0 (RSS_UNDEF) but
Line 12598... Line 15370...
    case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
    case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
    case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
    case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
    case BFD_RELOC_MIPS_TLS_GOTTPREL:
    case BFD_RELOC_MIPS_TLS_GOTTPREL:
    case BFD_RELOC_MIPS_TLS_TPREL_HI16:
    case BFD_RELOC_MIPS_TLS_TPREL_HI16:
    case BFD_RELOC_MIPS_TLS_TPREL_LO16:
    case BFD_RELOC_MIPS_TLS_TPREL_LO16:
 
    case BFD_RELOC_MICROMIPS_TLS_GD:
 
    case BFD_RELOC_MICROMIPS_TLS_LDM:
 
    case BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16:
 
    case BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16:
 
    case BFD_RELOC_MICROMIPS_TLS_GOTTPREL:
 
    case BFD_RELOC_MICROMIPS_TLS_TPREL_HI16:
 
    case BFD_RELOC_MICROMIPS_TLS_TPREL_LO16:
      S_SET_THREAD_LOCAL (fixP->fx_addsy);
      S_SET_THREAD_LOCAL (fixP->fx_addsy);
      /* fall through */
      /* fall through */
 
 
    case BFD_RELOC_MIPS_JMP:
    case BFD_RELOC_MIPS_JMP:
    case BFD_RELOC_MIPS_SHIFT5:
    case BFD_RELOC_MIPS_SHIFT5:
Line 12634... Line 15413...
    case BFD_RELOC_MIPS16_GOT16:
    case BFD_RELOC_MIPS16_GOT16:
    case BFD_RELOC_MIPS16_CALL16:
    case BFD_RELOC_MIPS16_CALL16:
    case BFD_RELOC_MIPS16_HI16:
    case BFD_RELOC_MIPS16_HI16:
    case BFD_RELOC_MIPS16_HI16_S:
    case BFD_RELOC_MIPS16_HI16_S:
    case BFD_RELOC_MIPS16_JMP:
    case BFD_RELOC_MIPS16_JMP:
 
    case BFD_RELOC_MICROMIPS_JMP:
 
    case BFD_RELOC_MICROMIPS_GOT_DISP:
 
    case BFD_RELOC_MICROMIPS_GOT_PAGE:
 
    case BFD_RELOC_MICROMIPS_GOT_OFST:
 
    case BFD_RELOC_MICROMIPS_SUB:
 
    case BFD_RELOC_MICROMIPS_HIGHEST:
 
    case BFD_RELOC_MICROMIPS_HIGHER:
 
    case BFD_RELOC_MICROMIPS_SCN_DISP:
 
    case BFD_RELOC_MICROMIPS_JALR:
 
    case BFD_RELOC_MICROMIPS_HI16:
 
    case BFD_RELOC_MICROMIPS_HI16_S:
 
    case BFD_RELOC_MICROMIPS_GPREL16:
 
    case BFD_RELOC_MICROMIPS_LITERAL:
 
    case BFD_RELOC_MICROMIPS_CALL16:
 
    case BFD_RELOC_MICROMIPS_GOT16:
 
    case BFD_RELOC_MICROMIPS_GOT_HI16:
 
    case BFD_RELOC_MICROMIPS_GOT_LO16:
 
    case BFD_RELOC_MICROMIPS_CALL_HI16:
 
    case BFD_RELOC_MICROMIPS_CALL_LO16:
      /* Nothing needed to do.  The value comes from the reloc entry.  */
      /* Nothing needed to do.  The value comes from the reloc entry.  */
      break;
      break;
 
 
    case BFD_RELOC_64:
    case BFD_RELOC_64:
      /* This is handled like BFD_RELOC_32, but we output a sign
      /* This is handled like BFD_RELOC_32, but we output a sign
Line 12672... Line 15470...
        md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
        md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
      break;
      break;
 
 
    case BFD_RELOC_LO16:
    case BFD_RELOC_LO16:
    case BFD_RELOC_MIPS16_LO16:
    case BFD_RELOC_MIPS16_LO16:
 
    case BFD_RELOC_MICROMIPS_LO16:
      /* FIXME: Now that embedded-PIC is gone, some of this code/comment
      /* FIXME: Now that embedded-PIC is gone, some of this code/comment
         may be safe to remove, but if so it's not obvious.  */
         may be safe to remove, but if so it's not obvious.  */
      /* When handling an embedded PIC switch statement, we can wind
      /* When handling an embedded PIC switch statement, we can wind
         up deleting a LO16 reloc.  See the 'o' case in mips_ip.  */
         up deleting a LO16 reloc.  See the 'o' case in mips_ip.  */
      if (fixP->fx_done)
      if (fixP->fx_done)
        {
        {
          if (*valP + 0x8000 > 0xffff)
          if (*valP + 0x8000 > 0xffff)
            as_bad_where (fixP->fx_file, fixP->fx_line,
            as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("relocation overflow"));
                          _("relocation overflow"));
          if (target_big_endian)
          /* 32-bit microMIPS instructions are divided into two halfwords.
 
             Relocations always refer to the second halfword, regardless
 
             of endianness.  */
 
          if (target_big_endian || fixP->fx_r_type == BFD_RELOC_MICROMIPS_LO16)
            buf += 2;
            buf += 2;
          md_number_to_chars ((char *) buf, *valP, 2);
          md_number_to_chars ((char *) buf, *valP, 2);
        }
        }
      break;
      break;
 
 
Line 12741... Line 15543...
          as_bad_where (fixP->fx_file, fixP->fx_line,
          as_bad_where (fixP->fx_file, fixP->fx_line,
                        _("Branch out of range"));
                        _("Branch out of range"));
        }
        }
      break;
      break;
 
 
 
    case BFD_RELOC_MICROMIPS_7_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_10_PCREL_S1:
 
    case BFD_RELOC_MICROMIPS_16_PCREL_S1:
 
      /* We adjust the offset back to even.  */
 
      if ((*valP & 0x1) != 0)
 
        --(*valP);
 
 
 
      if (! fixP->fx_done)
 
        break;
 
 
 
      /* Should never visit here, because we keep the relocation.  */
 
      abort ();
 
      break;
 
 
    case BFD_RELOC_VTABLE_INHERIT:
    case BFD_RELOC_VTABLE_INHERIT:
      fixP->fx_done = 0;
      fixP->fx_done = 0;
      if (fixP->fx_addsy
      if (fixP->fx_addsy
          && !S_IS_DEFINED (fixP->fx_addsy)
          && !S_IS_DEFINED (fixP->fx_addsy)
          && !S_IS_WEAK (fixP->fx_addsy))
          && !S_IS_WEAK (fixP->fx_addsy))
Line 12786... Line 15602...
 
 
static void
static void
mips_align (int to, int *fill, symbolS *label)
mips_align (int to, int *fill, symbolS *label)
{
{
  mips_emit_delays ();
  mips_emit_delays ();
  mips_record_mips16_mode ();
  mips_record_compressed_mode ();
  if (fill == NULL && subseg_text_p (now_seg))
  if (fill == NULL && subseg_text_p (now_seg))
    frag_align_code (to, 0);
    frag_align_code (to, 0);
  else
  else
    frag_align (to, fill ? *fill : 0, 0);
    frag_align (to, fill ? *fill : 0, 0);
  record_alignment (now_seg, to);
  record_alignment (now_seg, to);
Line 13251... Line 16067...
    mips_opts.single_float = 1;
    mips_opts.single_float = 1;
  else if (strcmp (name, "doublefloat") == 0)
  else if (strcmp (name, "doublefloat") == 0)
    mips_opts.single_float = 0;
    mips_opts.single_float = 0;
  else if (strcmp (name, "mips16") == 0
  else if (strcmp (name, "mips16") == 0
           || strcmp (name, "MIPS-16") == 0)
           || strcmp (name, "MIPS-16") == 0)
 
    {
 
      if (mips_opts.micromips == 1)
 
        as_fatal (_("`mips16' cannot be used with `micromips'"));
    mips_opts.mips16 = 1;
    mips_opts.mips16 = 1;
 
    }
  else if (strcmp (name, "nomips16") == 0
  else if (strcmp (name, "nomips16") == 0
           || strcmp (name, "noMIPS-16") == 0)
           || strcmp (name, "noMIPS-16") == 0)
    mips_opts.mips16 = 0;
    mips_opts.mips16 = 0;
 
  else if (strcmp (name, "micromips") == 0)
 
    {
 
      if (mips_opts.mips16 == 1)
 
        as_fatal (_("`micromips' cannot be used with `mips16'"));
 
      mips_opts.micromips = 1;
 
    }
 
  else if (strcmp (name, "nomicromips") == 0)
 
    mips_opts.micromips = 0;
  else if (strcmp (name, "smartmips") == 0)
  else if (strcmp (name, "smartmips") == 0)
    {
    {
      if (!ISA_SUPPORTS_SMARTMIPS)
      if (!ISA_SUPPORTS_SMARTMIPS)
        as_warn (_("%s ISA does not support SmartMIPS ASE"),
        as_warn (_("%s ISA does not support SmartMIPS ASE"),
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
Line 13307... Line 16135...
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
                 mips_cpu_info_from_isa (mips_opts.isa)->name);
      mips_opts.ase_mt = 1;
      mips_opts.ase_mt = 1;
    }
    }
  else if (strcmp (name, "nomt") == 0)
  else if (strcmp (name, "nomt") == 0)
    mips_opts.ase_mt = 0;
    mips_opts.ase_mt = 0;
 
  else if (strcmp (name, "mcu") == 0)
 
    mips_opts.ase_mcu = 1;
 
  else if (strcmp (name, "nomcu") == 0)
 
    mips_opts.ase_mcu = 0;
  else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
  else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
    {
    {
      int reset = 0;
      int reset = 0;
 
 
      /* Permit the user to change the ISA and architecture on the fly.
      /* Permit the user to change the ISA and architecture on the fly.
Line 13595... Line 16427...
    macro_build (NULL, "daddu", "d,v,t", mips_cpreturn_register,
    macro_build (NULL, "daddu", "d,v,t", mips_cpreturn_register,
                 mips_gp_register, 0);
                 mips_gp_register, 0);
 
 
  if (mips_in_shared || HAVE_64BIT_SYMBOLS)
  if (mips_in_shared || HAVE_64BIT_SYMBOLS)
    {
    {
      macro_build (&ex_sym, "lui", "t,u", mips_gp_register,
      macro_build (&ex_sym, "lui", LUI_FMT, mips_gp_register,
                   -1, BFD_RELOC_GPREL16, BFD_RELOC_MIPS_SUB,
                   -1, BFD_RELOC_GPREL16, BFD_RELOC_MIPS_SUB,
                   BFD_RELOC_HI16_S);
                   BFD_RELOC_HI16_S);
 
 
      macro_build (&ex_sym, "addiu", "t,r,j", mips_gp_register,
      macro_build (&ex_sym, "addiu", "t,r,j", mips_gp_register,
                   mips_gp_register, -1, BFD_RELOC_GPREL16,
                   mips_gp_register, -1, BFD_RELOC_GPREL16,
Line 13891... Line 16723...
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle the .insn pseudo-op.  This marks instruction labels in
/* Handle the .insn pseudo-op.  This marks instruction labels in
   mips16 mode.  This permits the linker to handle them specially,
   mips16/micromips mode.  This permits the linker to handle them specially,
   such as generating jalx instructions when needed.  We also make
   such as generating jalx instructions when needed.  We also make
   them odd for the duration of the assembly, in order to generate the
   them odd for the duration of the assembly, in order to generate the
   right sort of code.  We will make them even in the adjust_symtab
   right sort of code.  We will make them even in the adjust_symtab
   routine, while leaving them marked.  This is convenient for the
   routine, while leaving them marked.  This is convenient for the
   debugger and the disassembler.  The linker knows to make them odd
   debugger and the disassembler.  The linker knows to make them odd
   again.  */
   again.  */
 
 
static void
static void
s_insn (int ignore ATTRIBUTE_UNUSED)
s_insn (int ignore ATTRIBUTE_UNUSED)
{
{
  mips16_mark_labels ();
  mips_mark_labels ();
 
 
  demand_empty_rest_of_line ();
  demand_empty_rest_of_line ();
}
}
 
 
/* Handle a .stabn directive.  We need these in order to mark a label
/* Handle a .stabn directive.  We need these in order to mark a label
Line 13917... Line 16749...
 
 
static void
static void
s_mips_stab (int type)
s_mips_stab (int type)
{
{
  if (type == 'n')
  if (type == 'n')
    mips16_mark_labels ();
    mips_mark_labels ();
 
 
  s_stab (type);
  s_stab (type);
}
}
 
 
/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */
/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */
Line 14307... Line 17139...
          fragp->fr_subtype =
          fragp->fr_subtype =
            RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
            RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
          return 1;
          return 1;
        }
        }
    }
    }
  else if (symsec != absolute_section && sec != NULL)
  else if (symsec != absolute_section && sec != NULL)
    as_bad_where (fragp->fr_file, fragp->fr_line, _("unsupported relocation"));
    as_bad_where (fragp->fr_file, fragp->fr_line, _("unsupported relocation"));
 
 
 
  if ((val & ((1 << op->shift) - 1)) != 0
 
      || val < (mintiny << op->shift)
 
      || val > (maxtiny << op->shift))
 
    return 1;
 
  else
 
    return 0;
 
}
 
 
 
/* Compute the length of a branch sequence, and adjust the
 
   RELAX_BRANCH_TOOFAR bit accordingly.  If FRAGP is NULL, the
 
   worst-case length is computed, with UPDATE being used to indicate
 
   whether an unconditional (-1), branch-likely (+1) or regular (0)
 
   branch is to be computed.  */
 
static int
 
relaxed_branch_length (fragS *fragp, asection *sec, int update)
 
{
 
  bfd_boolean toofar;
 
  int length;
 
 
 
  if (fragp
 
      && S_IS_DEFINED (fragp->fr_symbol)
 
      && sec == S_GET_SEGMENT (fragp->fr_symbol))
 
    {
 
      addressT addr;
 
      offsetT val;
 
 
 
      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
 
 
 
      addr = fragp->fr_address + fragp->fr_fix + 4;
 
 
 
      val -= addr;
 
 
 
      toofar = val < - (0x8000 << 2) || val >= (0x8000 << 2);
 
    }
 
  else if (fragp)
 
    /* If the symbol is not defined or it's in a different segment,
 
       assume the user knows what's going on and emit a short
 
       branch.  */
 
    toofar = FALSE;
 
  else
 
    toofar = TRUE;
 
 
 
  if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
 
    fragp->fr_subtype
 
      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype),
 
                             RELAX_BRANCH_UNCOND (fragp->fr_subtype),
 
                             RELAX_BRANCH_LIKELY (fragp->fr_subtype),
 
                             RELAX_BRANCH_LINK (fragp->fr_subtype),
 
                             toofar);
 
 
 
  length = 4;
 
  if (toofar)
 
    {
 
      if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0))
 
        length += 8;
 
 
 
      if (mips_pic != NO_PIC)
 
        {
 
          /* Additional space for PIC loading of target address.  */
 
          length += 8;
 
          if (mips_opts.isa == ISA_MIPS1)
 
            /* Additional space for $at-stabilizing nop.  */
 
            length += 4;
 
        }
 
 
 
      /* If branch is conditional.  */
 
      if (fragp ? !RELAX_BRANCH_UNCOND (fragp->fr_subtype) : (update >= 0))
 
        length += 8;
 
    }
 
 
 
  return length;
 
}
 
 
 
/* Compute the length of a branch sequence, and adjust the
 
   RELAX_MICROMIPS_TOOFAR32 bit accordingly.  If FRAGP is NULL, the
 
   worst-case length is computed, with UPDATE being used to indicate
 
   whether an unconditional (-1), or regular (0) branch is to be
 
   computed.  */
 
 
 
static int
 
relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update)
 
{
 
  bfd_boolean toofar;
 
  int length;
 
 
 
  if (fragp
 
      && S_IS_DEFINED (fragp->fr_symbol)
 
      && sec == S_GET_SEGMENT (fragp->fr_symbol))
 
    {
 
      addressT addr;
 
      offsetT val;
 
 
 
      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
 
      /* Ignore the low bit in the target, since it will be set
 
         for a text label.  */
 
      if ((val & 1) != 0)
 
        --val;
 
 
 
      addr = fragp->fr_address + fragp->fr_fix + 4;
 
 
 
      val -= addr;
 
 
 
      toofar = val < - (0x8000 << 1) || val >= (0x8000 << 1);
 
    }
 
  else if (fragp)
 
    /* If the symbol is not defined or it's in a different segment,
 
       assume the user knows what's going on and emit a short
 
       branch.  */
 
    toofar = FALSE;
 
  else
 
    toofar = TRUE;
 
 
 
  if (fragp && update
 
      && toofar != RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
 
    fragp->fr_subtype = (toofar
 
                         ? RELAX_MICROMIPS_MARK_TOOFAR32 (fragp->fr_subtype)
 
                         : RELAX_MICROMIPS_CLEAR_TOOFAR32 (fragp->fr_subtype));
 
 
 
  length = 4;
 
  if (toofar)
 
    {
 
      bfd_boolean compact_known = fragp != NULL;
 
      bfd_boolean compact = FALSE;
 
      bfd_boolean uncond;
 
 
 
      if (compact_known)
 
        compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
 
      if (fragp)
 
        uncond = RELAX_MICROMIPS_UNCOND (fragp->fr_subtype);
 
      else
 
        uncond = update < 0;
 
 
 
      /* If label is out of range, we turn branch <br>:
 
 
 
                <br>    label                   # 4 bytes
 
            0:
 
 
 
         into:
 
 
 
                j       label                   # 4 bytes
 
                nop                             # 2 bytes if compact && !PIC
 
            0:
 
       */
 
      if (mips_pic == NO_PIC && (!compact_known || compact))
 
        length += 2;
 
 
 
      /* If assembling PIC code, we further turn:
 
 
 
                        j       label                   # 4 bytes
 
 
 
         into:
 
 
 
                        lw/ld   at, %got(label)(gp)     # 4 bytes
 
                        d/addiu at, %lo(label)          # 4 bytes
 
                        jr/c    at                      # 2 bytes
 
       */
 
      if (mips_pic != NO_PIC)
 
        length += 6;
 
 
 
      /* If branch <br> is conditional, we prepend negated branch <brneg>:
 
 
 
                        <brneg> 0f                      # 4 bytes
 
                        nop                             # 2 bytes if !compact
 
       */
 
      if (!uncond)
 
        length += (compact_known && compact) ? 4 : 6;
 
    }
 
 
  if ((val & ((1 << op->shift) - 1)) != 0
  return length;
      || val < (mintiny << op->shift)
 
      || val > (maxtiny << op->shift))
 
    return 1;
 
  else
 
    return 0;
 
}
}
 
 
/* Compute the length of a branch sequence, and adjust the
/* Compute the length of a branch, and adjust the RELAX_MICROMIPS_TOOFAR16
   RELAX_BRANCH_TOOFAR bit accordingly.  If FRAGP is NULL, the
   bit accordingly.  */
   worst-case length is computed, with UPDATE being used to indicate
 
   whether an unconditional (-1), branch-likely (+1) or regular (0)
 
   branch is to be computed.  */
 
static int
static int
relaxed_branch_length (fragS *fragp, asection *sec, int update)
relaxed_micromips_16bit_branch_length (fragS *fragp, asection *sec, int update)
{
{
  bfd_boolean toofar;
  bfd_boolean toofar;
  int length;
 
 
 
  if (fragp
  if (fragp
      && S_IS_DEFINED (fragp->fr_symbol)
      && S_IS_DEFINED (fragp->fr_symbol)
      && sec == S_GET_SEGMENT (fragp->fr_symbol))
      && sec == S_GET_SEGMENT (fragp->fr_symbol))
    {
    {
      addressT addr;
      addressT addr;
      offsetT val;
      offsetT val;
 
      int type;
 
 
      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
 
      /* Ignore the low bit in the target, since it will be set
 
         for a text label.  */
 
      if ((val & 1) != 0)
 
        --val;
 
 
      addr = fragp->fr_address + fragp->fr_fix + 4;
      /* Assume this is a 2-byte branch.  */
 
      addr = fragp->fr_address + fragp->fr_fix + 2;
 
 
 
      /* We try to avoid the infinite loop by not adding 2 more bytes for
 
         long branches.  */
 
 
      val -= addr;
      val -= addr;
 
 
      toofar = val < - (0x8000 << 2) || val >= (0x8000 << 2);
      type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
 
      if (type == 'D')
 
        toofar = val < - (0x200 << 1) || val >= (0x200 << 1);
 
      else if (type == 'E')
 
        toofar = val < - (0x40 << 1) || val >= (0x40 << 1);
 
      else
 
        abort ();
    }
    }
  else if (fragp)
 
    /* If the symbol is not defined or it's in a different segment,
 
       assume the user knows what's going on and emit a short
 
       branch.  */
 
    toofar = FALSE;
 
  else
  else
 
    /* If the symbol is not defined or it's in a different segment,
 
       we emit a normal 32-bit branch.  */
    toofar = TRUE;
    toofar = TRUE;
 
 
  if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
  if (fragp && update
 
      && toofar != RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
    fragp->fr_subtype
    fragp->fr_subtype
      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype),
      = toofar ? RELAX_MICROMIPS_MARK_TOOFAR16 (fragp->fr_subtype)
                             RELAX_BRANCH_UNCOND (fragp->fr_subtype),
               : RELAX_MICROMIPS_CLEAR_TOOFAR16 (fragp->fr_subtype);
                             RELAX_BRANCH_LIKELY (fragp->fr_subtype),
 
                             RELAX_BRANCH_LINK (fragp->fr_subtype),
 
                             toofar);
 
 
 
  length = 4;
 
  if (toofar)
  if (toofar)
    {
    return 4;
      if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0))
 
        length += 8;
 
 
 
      if (mips_pic != NO_PIC)
 
        {
 
          /* Additional space for PIC loading of target address.  */
 
          length += 8;
 
          if (mips_opts.isa == ISA_MIPS1)
 
            /* Additional space for $at-stabilizing nop.  */
 
            length += 4;
 
        }
 
 
 
      /* If branch is conditional.  */
 
      if (fragp ? !RELAX_BRANCH_UNCOND (fragp->fr_subtype) : (update >= 0))
 
        length += 8;
 
    }
 
 
 
  return length;
  return 2;
}
}
 
 
/* Estimate the size of a frag before relaxing.  Unless this is the
/* Estimate the size of a frag before relaxing.  Unless this is the
   mips16, we are not really relaxing here, and the final size is
   mips16, we are not really relaxing here, and the final size is
   encoded in the subtype information.  For the mips16, we have to
   encoded in the subtype information.  For the mips16, we have to
Line 14406... Line 17391...
  if (RELAX_MIPS16_P (fragp->fr_subtype))
  if (RELAX_MIPS16_P (fragp->fr_subtype))
    /* We don't want to modify the EXTENDED bit here; it might get us
    /* We don't want to modify the EXTENDED bit here; it might get us
       into infinite loops.  We change it only in mips_relax_frag().  */
       into infinite loops.  We change it only in mips_relax_frag().  */
    return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
    return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
 
 
 
  if (RELAX_MICROMIPS_P (fragp->fr_subtype))
 
    {
 
      int length = 4;
 
 
 
      if (RELAX_MICROMIPS_TYPE (fragp->fr_subtype) != 0)
 
        length = relaxed_micromips_16bit_branch_length (fragp, segtype, FALSE);
 
      if (length == 4 && RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype))
 
        length = relaxed_micromips_32bit_branch_length (fragp, segtype, FALSE);
 
      fragp->fr_var = length;
 
 
 
      return length;
 
    }
 
 
  if (mips_pic == NO_PIC)
  if (mips_pic == NO_PIC)
    change = nopic_need_relax (fragp->fr_symbol, 0);
    change = nopic_need_relax (fragp->fr_symbol, 0);
  else if (mips_pic == SVR4_PIC)
  else if (mips_pic == SVR4_PIC)
    change = pic_need_relax (fragp->fr_symbol, segtype);
    change = pic_need_relax (fragp->fr_symbol, segtype);
  else if (mips_pic == VXWORKS_PIC)
  else if (mips_pic == VXWORKS_PIC)
Line 14463... Line 17461...
  /* There is no place to store an in-place offset for JALR relocations.
  /* There is no place to store an in-place offset for JALR relocations.
     Likewise an in-range offset of PC-relative relocations may overflow
     Likewise an in-range offset of PC-relative relocations may overflow
     the in-place relocatable field if recalculated against the start
     the in-place relocatable field if recalculated against the start
     address of the symbol's containing section.  */
     address of the symbol's containing section.  */
  if (HAVE_IN_PLACE_ADDENDS
  if (HAVE_IN_PLACE_ADDENDS
      && (fixp->fx_pcrel || fixp->fx_r_type == BFD_RELOC_MIPS_JALR))
      && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type)))
    return 0;
    return 0;
 
 
#ifdef OBJ_ELF
#ifdef OBJ_ELF
  /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
  /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
     to a floating-point stub.  The same is true for non-R_MIPS16_26
     to a floating-point stub.  The same is true for non-R_MIPS16_26
Line 14493... Line 17491...
       4. We cannot reduce a stub's relocations against MIPS16 symbols if
       4. We cannot reduce a stub's relocations against MIPS16 symbols if
          that stub might be used.
          that stub might be used.
 
 
     There is a further restriction:
     There is a further restriction:
 
 
       5. We cannot reduce R_MIPS16_26 relocations against MIPS16 symbols
       5. We cannot reduce jump relocations (R_MIPS_26, R_MIPS16_26 or
          on targets with in-place addends; the relocation field cannot
          R_MICROMIPS_26_S1) against MIPS16 or microMIPS symbols on
 
          targets with in-place addends; the relocation field cannot
          encode the low bit.
          encode the low bit.
 
 
     For simplicity, we deal with (3)-(5) by not reducing _any_ relocation
     For simplicity, we deal with (3)-(4) by not reducing _any_ relocation
     against a MIPS16 symbol.
     against a MIPS16 symbol.  We deal with (5) by by not reducing any
 
     such relocations on REL targets.
 
 
     We deal with (1)-(2) by saying that, if there's a R_MIPS16_26
     We deal with (1)-(2) by saying that, if there's a R_MIPS16_26
     relocation against some symbol R, no relocation against R may be
     relocation against some symbol R, no relocation against R may be
     reduced.  (Note that this deals with (2) as well as (1) because
     reduced.  (Note that this deals with (2) as well as (1) because
     relocations against global symbols will never be reduced on ELF
     relocations against global symbols will never be reduced on ELF
Line 14510... Line 17510...
     stub sections, and gives the "all or nothing" per-symbol consistency
     stub sections, and gives the "all or nothing" per-symbol consistency
     that we have for MIPS16 symbols.  */
     that we have for MIPS16 symbols.  */
  if (IS_ELF
  if (IS_ELF
      && fixp->fx_subsy == NULL
      && fixp->fx_subsy == NULL
      && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
      && (ELF_ST_IS_MIPS16 (S_GET_OTHER (fixp->fx_addsy))
          || *symbol_get_tc (fixp->fx_addsy)))
          || *symbol_get_tc (fixp->fx_addsy)
 
          || (HAVE_IN_PLACE_ADDENDS
 
              && ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy))
 
              && jmp_reloc_p (fixp->fx_r_type))))
    return 0;
    return 0;
#endif
#endif
 
 
  return 1;
  return 1;
}
}
Line 14535... Line 17538...
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
 
  if (fixp->fx_pcrel)
  if (fixp->fx_pcrel)
    {
    {
      gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
      gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
 
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1
 
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1
 
                  || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1);
 
 
      /* At this point, fx_addnumber is "symbol offset - pcrel address".
      /* At this point, fx_addnumber is "symbol offset - pcrel address".
         Relocations want only the symbol offset.  */
         Relocations want only the symbol offset.  */
      reloc->addend = fixp->fx_addnumber + reloc->address;
      reloc->addend = fixp->fx_addnumber + reloc->address;
      if (!IS_ELF)
      if (!IS_ELF)
Line 14589... Line 17595...
      fragp->fr_var = relaxed_branch_length (fragp, sec, TRUE);
      fragp->fr_var = relaxed_branch_length (fragp, sec, TRUE);
 
 
      return fragp->fr_var - old_var;
      return fragp->fr_var - old_var;
    }
    }
 
 
 
  if (RELAX_MICROMIPS_P (fragp->fr_subtype))
 
    {
 
      offsetT old_var = fragp->fr_var;
 
      offsetT new_var = 4;
 
 
 
      if (RELAX_MICROMIPS_TYPE (fragp->fr_subtype) != 0)
 
        new_var = relaxed_micromips_16bit_branch_length (fragp, sec, TRUE);
 
      if (new_var == 4 && RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype))
 
        new_var = relaxed_micromips_32bit_branch_length (fragp, sec, TRUE);
 
      fragp->fr_var = new_var;
 
 
 
      return new_var - old_var;
 
    }
 
 
  if (! RELAX_MIPS16_P (fragp->fr_subtype))
  if (! RELAX_MIPS16_P (fragp->fr_subtype))
    return 0;
    return 0;
 
 
  if (mips16_extended_frag (fragp, NULL, stretch))
  if (mips16_extended_frag (fragp, NULL, stretch))
    {
    {
Line 14827... Line 17847...
      fragp->fr_fix += fragp->fr_var;
      fragp->fr_fix += fragp->fr_var;
 
 
      return;
      return;
    }
    }
 
 
 
  /* Relax microMIPS branches.  */
 
  if (RELAX_MICROMIPS_P (fragp->fr_subtype))
 
    {
 
      bfd_byte *buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
 
      bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
 
      bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
 
      int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
 
      bfd_boolean short_ds;
 
      unsigned long insn;
 
      expressionS exp;
 
      fixS *fixp;
 
 
 
      exp.X_op = O_symbol;
 
      exp.X_add_symbol = fragp->fr_symbol;
 
      exp.X_add_number = fragp->fr_offset;
 
 
 
      fragp->fr_fix += fragp->fr_var;
 
 
 
      /* Handle 16-bit branches that fit or are forced to fit.  */
 
      if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype))
 
        {
 
          /* We generate a fixup instead of applying it right now,
 
             because if there is linker relaxation, we're going to
 
             need the relocations.  */
 
          if (type == 'D')
 
            fixp = fix_new_exp (fragp,
 
                                buf - (bfd_byte *) fragp->fr_literal,
 
                                2, &exp, TRUE,
 
                                BFD_RELOC_MICROMIPS_10_PCREL_S1);
 
          else if (type == 'E')
 
            fixp = fix_new_exp (fragp,
 
                                buf - (bfd_byte *) fragp->fr_literal,
 
                                2, &exp, TRUE,
 
                                BFD_RELOC_MICROMIPS_7_PCREL_S1);
 
          else
 
            abort ();
 
 
 
          fixp->fx_file = fragp->fr_file;
 
          fixp->fx_line = fragp->fr_line;
 
 
 
          /* These relocations can have an addend that won't fit in
 
             2 octets.  */
 
          fixp->fx_no_overflow = 1;
 
 
 
          return;
 
        }
 
 
 
      /* Handle 32-bit branches that fit or are forced to fit.  */
 
      if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
 
          || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
 
        {
 
          /* We generate a fixup instead of applying it right now,
 
             because if there is linker relaxation, we're going to
 
             need the relocations.  */
 
          fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
 
                              4, &exp, TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
 
          fixp->fx_file = fragp->fr_file;
 
          fixp->fx_line = fragp->fr_line;
 
 
 
          if (type == 0)
 
            return;
 
        }
 
 
 
      /* Relax 16-bit branches to 32-bit branches.  */
 
      if (type != 0)
 
        {
 
          if (target_big_endian)
 
            insn = bfd_getb16 (buf);
 
          else
 
            insn = bfd_getl16 (buf);
 
 
 
          if ((insn & 0xfc00) == 0xcc00)                /* b16  */
 
            insn = 0x94000000;                          /* beq  */
 
          else if ((insn & 0xdc00) == 0x8c00)           /* beqz16/bnez16  */
 
            {
 
              unsigned long regno;
 
 
 
              regno = (insn >> MICROMIPSOP_SH_MD) & MICROMIPSOP_MASK_MD;
 
              regno = micromips_to_32_reg_d_map [regno];
 
              insn = ((insn & 0x2000) << 16) | 0x94000000;      /* beq/bne  */
 
              insn |= regno << MICROMIPSOP_SH_RS;
 
            }
 
          else
 
            abort ();
 
 
 
          /* Nothing else to do, just write it out.  */
 
          if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
 
              || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
 
            {
 
              md_number_to_chars ((char *) buf, insn >> 16, 2);
 
              buf += 2;
 
              md_number_to_chars ((char *) buf, insn & 0xffff, 2);
 
              buf += 2;
 
 
 
              gas_assert (buf == ((bfd_byte *) fragp->fr_literal
 
                                  + fragp->fr_fix));
 
              return;
 
            }
 
        }
 
      else
 
        {
 
          unsigned long next;
 
 
 
          if (target_big_endian)
 
            {
 
              insn = bfd_getb16 (buf);
 
              next = bfd_getb16 (buf + 2);
 
            }
 
          else
 
            {
 
              insn = bfd_getl16 (buf);
 
              next = bfd_getl16 (buf + 2);
 
            }
 
          insn = (insn << 16) | next;
 
        }
 
 
 
      /* Relax 32-bit branches to a sequence of instructions.  */
 
      as_warn_where (fragp->fr_file, fragp->fr_line,
 
                     _("Relaxed out-of-range branch into a jump"));
 
 
 
      /* Set the short-delay-slot bit.  */
 
      short_ds = al && (insn & 0x02000000) != 0;
 
 
 
      if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
 
        {
 
          symbolS *l;
 
 
 
          /* Reverse the branch.  */
 
          if ((insn & 0xfc000000) == 0x94000000                 /* beq  */
 
              || (insn & 0xfc000000) == 0xb4000000)             /* bne  */
 
            insn ^= 0x20000000;
 
          else if ((insn & 0xffe00000) == 0x40000000            /* bltz  */
 
                   || (insn & 0xffe00000) == 0x40400000         /* bgez  */
 
                   || (insn & 0xffe00000) == 0x40800000         /* blez  */
 
                   || (insn & 0xffe00000) == 0x40c00000         /* bgtz  */
 
                   || (insn & 0xffe00000) == 0x40a00000         /* bnezc  */
 
                   || (insn & 0xffe00000) == 0x40e00000         /* beqzc  */
 
                   || (insn & 0xffe00000) == 0x40200000         /* bltzal  */
 
                   || (insn & 0xffe00000) == 0x40600000         /* bgezal  */
 
                   || (insn & 0xffe00000) == 0x42200000         /* bltzals  */
 
                   || (insn & 0xffe00000) == 0x42600000)        /* bgezals  */
 
            insn ^= 0x00400000;
 
          else if ((insn & 0xffe30000) == 0x43800000            /* bc1f  */
 
                   || (insn & 0xffe30000) == 0x43a00000         /* bc1t  */
 
                   || (insn & 0xffe30000) == 0x42800000         /* bc2f  */
 
                   || (insn & 0xffe30000) == 0x42a00000)        /* bc2t  */
 
            insn ^= 0x00200000;
 
          else
 
            abort ();
 
 
 
          if (al)
 
            {
 
              /* Clear the and-link and short-delay-slot bits.  */
 
              gas_assert ((insn & 0xfda00000) == 0x40200000);
 
 
 
              /* bltzal  0x40200000     bgezal  0x40600000  */
 
              /* bltzals 0x42200000     bgezals 0x42600000  */
 
              insn &= ~0x02200000;
 
            }
 
 
 
          /* Make a label at the end for use with the branch.  */
 
          l = symbol_new (micromips_label_name (), asec, fragp->fr_fix, fragp);
 
          micromips_label_inc ();
 
#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
 
          if (IS_ELF)
 
            S_SET_OTHER (l, ELF_ST_SET_MICROMIPS (S_GET_OTHER (l)));
 
#endif
 
 
 
          /* Refer to it.  */
 
          fixp = fix_new (fragp, buf - (bfd_byte *) fragp->fr_literal,
 
                          4, l, 0, TRUE, BFD_RELOC_MICROMIPS_16_PCREL_S1);
 
          fixp->fx_file = fragp->fr_file;
 
          fixp->fx_line = fragp->fr_line;
 
 
 
          /* Branch over the jump.  */
 
          md_number_to_chars ((char *) buf, insn >> 16, 2);
 
          buf += 2;
 
          md_number_to_chars ((char *) buf, insn & 0xffff, 2);
 
          buf += 2;
 
 
 
          if (!compact)
 
            {
 
              /* nop  */
 
              insn = 0x0c00;
 
              md_number_to_chars ((char *) buf, insn, 2);
 
              buf += 2;
 
            }
 
        }
 
 
 
      if (mips_pic == NO_PIC)
 
        {
 
          unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s  */
 
 
 
          /* j/jal/jals <sym>  R_MICROMIPS_26_S1  */
 
          insn = al ? jal : 0xd4000000;
 
 
 
          fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
 
                              4, &exp, FALSE, BFD_RELOC_MICROMIPS_JMP);
 
          fixp->fx_file = fragp->fr_file;
 
          fixp->fx_line = fragp->fr_line;
 
 
 
          md_number_to_chars ((char *) buf, insn >> 16, 2);
 
          buf += 2;
 
          md_number_to_chars ((char *) buf, insn & 0xffff, 2);
 
          buf += 2;
 
 
 
          if (compact)
 
            {
 
              /* nop  */
 
              insn = 0x0c00;
 
              md_number_to_chars ((char *) buf, insn, 2);
 
              buf += 2;
 
            }
 
        }
 
      else
 
        {
 
          unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype);
 
          unsigned long jalr = short_ds ? 0x45e0 : 0x45c0;      /* jalr/s  */
 
          unsigned long jr = compact ? 0x45a0 : 0x4580;         /* jr/c  */
 
 
 
          /* lw/ld $at, <sym>($gp)  R_MICROMIPS_GOT16  */
 
          insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;
 
          insn |= at << MICROMIPSOP_SH_RT;
 
 
 
          if (exp.X_add_number)
 
            {
 
              exp.X_add_symbol = make_expr_symbol (&exp);
 
              exp.X_add_number = 0;
 
            }
 
 
 
          fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
 
                              4, &exp, FALSE, BFD_RELOC_MICROMIPS_GOT16);
 
          fixp->fx_file = fragp->fr_file;
 
          fixp->fx_line = fragp->fr_line;
 
 
 
          md_number_to_chars ((char *) buf, insn >> 16, 2);
 
          buf += 2;
 
          md_number_to_chars ((char *) buf, insn & 0xffff, 2);
 
          buf += 2;
 
 
 
          /* d/addiu $at, $at, <sym>  R_MICROMIPS_LO16  */
 
          insn = HAVE_64BIT_ADDRESSES ? 0x5c000000 : 0x30000000;
 
          insn |= at << MICROMIPSOP_SH_RT | at << MICROMIPSOP_SH_RS;
 
 
 
          fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
 
                              4, &exp, FALSE, BFD_RELOC_MICROMIPS_LO16);
 
          fixp->fx_file = fragp->fr_file;
 
          fixp->fx_line = fragp->fr_line;
 
 
 
          md_number_to_chars ((char *) buf, insn >> 16, 2);
 
          buf += 2;
 
          md_number_to_chars ((char *) buf, insn & 0xffff, 2);
 
          buf += 2;
 
 
 
          /* jr/jrc/jalr/jalrs $at  */
 
          insn = al ? jalr : jr;
 
          insn |= at << MICROMIPSOP_SH_MJ;
 
 
 
          md_number_to_chars ((char *) buf, insn & 0xffff, 2);
 
          buf += 2;
 
        }
 
 
 
      gas_assert (buf == (bfd_byte *) fragp->fr_literal + fragp->fr_fix);
 
      return;
 
    }
 
 
  if (RELAX_MIPS16_P (fragp->fr_subtype))
  if (RELAX_MIPS16_P (fragp->fr_subtype))
    {
    {
      int type;
      int type;
      const struct mips16_immed_operand *op;
      const struct mips16_immed_operand *op;
      bfd_boolean small, ext;
      bfd_boolean small, ext;
Line 14917... Line 18203...
      fragp->fr_fix += 2;
      fragp->fr_fix += 2;
      buf += 2;
      buf += 2;
    }
    }
  else
  else
    {
    {
 
      relax_substateT subtype = fragp->fr_subtype;
 
      bfd_boolean second_longer = (subtype & RELAX_SECOND_LONGER) != 0;
 
      bfd_boolean use_second = (subtype & RELAX_USE_SECOND) != 0;
      int first, second;
      int first, second;
      fixS *fixp;
      fixS *fixp;
 
 
      first = RELAX_FIRST (fragp->fr_subtype);
      first = RELAX_FIRST (subtype);
      second = RELAX_SECOND (fragp->fr_subtype);
      second = RELAX_SECOND (subtype);
      fixp = (fixS *) fragp->fr_opcode;
      fixp = (fixS *) fragp->fr_opcode;
 
 
 
      /* If the delay slot chosen does not match the size of the instruction,
 
         then emit a warning.  */
 
      if ((!use_second && (subtype & RELAX_DELAY_SLOT_SIZE_FIRST) != 0)
 
           || (use_second && (subtype & RELAX_DELAY_SLOT_SIZE_SECOND) != 0))
 
        {
 
          relax_substateT s;
 
          const char *msg;
 
 
 
          s = subtype & (RELAX_DELAY_SLOT_16BIT
 
                         | RELAX_DELAY_SLOT_SIZE_FIRST
 
                         | RELAX_DELAY_SLOT_SIZE_SECOND);
 
          msg = macro_warning (s);
 
          if (msg != NULL)
 
            as_warn_where (fragp->fr_file, fragp->fr_line, msg);
 
          subtype &= ~s;
 
        }
 
 
      /* Possibly emit a warning if we've chosen the longer option.  */
      /* Possibly emit a warning if we've chosen the longer option.  */
      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
      if (use_second == second_longer)
          == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
 
        {
        {
          const char *msg = macro_warning (fragp->fr_subtype);
          relax_substateT s;
          if (msg != 0)
          const char *msg;
            as_warn_where (fragp->fr_file, fragp->fr_line, "%s", msg);
 
 
          s = (subtype
 
               & (RELAX_SECOND_LONGER | RELAX_NOMACRO | RELAX_DELAY_SLOT));
 
          msg = macro_warning (s);
 
          if (msg != NULL)
 
            as_warn_where (fragp->fr_file, fragp->fr_line, msg);
 
          subtype &= ~s;
        }
        }
 
 
      /* Go through all the fixups for the first sequence.  Disable them
      /* Go through all the fixups for the first sequence.  Disable them
         (by marking them as done) if we're going to use the second
         (by marking them as done) if we're going to use the second
         sequence instead.  */
         sequence instead.  */
      while (fixp
      while (fixp
             && fixp->fx_frag == fragp
             && fixp->fx_frag == fragp
             && fixp->fx_where < fragp->fr_fix - second)
             && fixp->fx_where < fragp->fr_fix - second)
        {
        {
          if (fragp->fr_subtype & RELAX_USE_SECOND)
          if (subtype & RELAX_USE_SECOND)
            fixp->fx_done = 1;
            fixp->fx_done = 1;
          fixp = fixp->fx_next;
          fixp = fixp->fx_next;
        }
        }
 
 
      /* Go through the fixups for the second sequence.  Disable them if
      /* Go through the fixups for the second sequence.  Disable them if
         we're going to use the first sequence, otherwise adjust their
         we're going to use the first sequence, otherwise adjust their
         addresses to account for the relaxation.  */
         addresses to account for the relaxation.  */
      while (fixp && fixp->fx_frag == fragp)
      while (fixp && fixp->fx_frag == fragp)
        {
        {
          if (fragp->fr_subtype & RELAX_USE_SECOND)
          if (subtype & RELAX_USE_SECOND)
            fixp->fx_where -= first;
            fixp->fx_where -= first;
          else
          else
            fixp->fx_done = 1;
            fixp->fx_done = 1;
          fixp = fixp->fx_next;
          fixp = fixp->fx_next;
        }
        }
 
 
      /* Now modify the frag contents.  */
      /* Now modify the frag contents.  */
      if (fragp->fr_subtype & RELAX_USE_SECOND)
      if (subtype & RELAX_USE_SECOND)
        {
        {
          char *start;
          char *start;
 
 
          start = fragp->fr_literal + fragp->fr_fix - first - second;
          start = fragp->fr_literal + fragp->fr_fix - first - second;
          memmove (start, start + first, second);
          memmove (start, start + first, second);
Line 14989... Line 18300...
    return;
    return;
 
 
  syms = bfd_get_outsymbols (stdoutput);
  syms = bfd_get_outsymbols (stdoutput);
  count = bfd_get_symcount (stdoutput);
  count = bfd_get_symcount (stdoutput);
  for (i = 0; i < count; i++, syms++)
  for (i = 0; i < count; i++, syms++)
    {
    if (ELF_ST_IS_COMPRESSED (elf_symbol (*syms)->internal_elf_sym.st_other)
      if (ELF_ST_IS_MIPS16 (elf_symbol (*syms)->internal_elf_sym.st_other)
 
          && ((*syms)->value & 1) != 0)
          && ((*syms)->value & 1) != 0)
        {
        {
          (*syms)->value &= ~1;
          (*syms)->value &= ~1;
          /* If the symbol has an odd size, it was probably computed
          /* If the symbol has an odd size, it was probably computed
             incorrectly, so adjust that as well.  */
             incorrectly, so adjust that as well.  */
          if ((elf_symbol (*syms)->internal_elf_sym.st_size & 1) != 0)
          if ((elf_symbol (*syms)->internal_elf_sym.st_size & 1) != 0)
            ++elf_symbol (*syms)->internal_elf_sym.st_size;
            ++elf_symbol (*syms)->internal_elf_sym.st_size;
        }
        }
    }
    }
}
 
 
 
#endif
#endif
 
 
/* This function is called whenever a label is defined, including fake
/* This function is called whenever a label is defined, including fake
   labels instantiated off the dot special symbol.  It is used when
   labels instantiated off the dot special symbol.  It is used when
Line 15101... Line 18410...
  /* Same for DSP R2.  */
  /* Same for DSP R2.  */
  /* We may need to define a new flag for MT ASE, and set this flag when
  /* We may need to define a new flag for MT ASE, and set this flag when
     file_ase_mt is true.  */
     file_ase_mt is true.  */
  if (file_ase_mips16)
  if (file_ase_mips16)
    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
 
  if (file_ase_micromips)
 
    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MICROMIPS;
#if 0 /* XXX FIXME */
#if 0 /* XXX FIXME */
  if (file_ase_mips3d)
  if (file_ase_mips3d)
    elf_elfheader (stdoutput)->e_flags |= ???;
    elf_elfheader (stdoutput)->e_flags |= ???;
#endif
#endif
  if (file_ase_mdmx)
  if (file_ase_mdmx)
Line 15153... Line 18464...
 
 
static procS cur_proc;
static procS cur_proc;
static procS *cur_proc_ptr;
static procS *cur_proc_ptr;
static int numprocs;
static int numprocs;
 
 
/* Implement NOP_OPCODE.  We encode a MIPS16 nop as "1" and a normal
/* Implement NOP_OPCODE.  We encode a MIPS16 nop as "1", a microMIPS nop
   nop as "0".  */
   as "2", and a normal nop as "0".  */
 
 
 
#define NOP_OPCODE_MIPS         0
 
#define NOP_OPCODE_MIPS16       1
 
#define NOP_OPCODE_MICROMIPS    2
 
 
char
char
mips_nop_opcode (void)
mips_nop_opcode (void)
{
{
  return seg_info (now_seg)->tc_segment_info_data.mips16;
  if (seg_info (now_seg)->tc_segment_info_data.micromips)
 
    return NOP_OPCODE_MICROMIPS;
 
  else if (seg_info (now_seg)->tc_segment_info_data.mips16)
 
    return NOP_OPCODE_MIPS16;
 
  else
 
    return NOP_OPCODE_MIPS;
}
}
 
 
/* Fill in an rs_align_code fragment.  This only needs to do something
/* Fill in an rs_align_code fragment.  Unlike elsewhere we want to use
   for MIPS16 code, where 0 is not a nop.  */
   32-bit microMIPS NOPs here (if applicable).  */
 
 
void
void
mips_handle_align (fragS *fragp)
mips_handle_align (fragS *fragp)
{
{
 
  char nop_opcode;
  char *p;
  char *p;
  int bytes, size, excess;
  int bytes, size, excess;
  valueT opcode;
  valueT opcode;
 
 
  if (fragp->fr_type != rs_align_code)
  if (fragp->fr_type != rs_align_code)
    return;
    return;
 
 
  p = fragp->fr_literal + fragp->fr_fix;
  p = fragp->fr_literal + fragp->fr_fix;
  if (*p)
  nop_opcode = *p;
 
  switch (nop_opcode)
    {
    {
 
    case NOP_OPCODE_MICROMIPS:
 
      opcode = micromips_nop32_insn.insn_opcode;
 
      size = 4;
 
      break;
 
    case NOP_OPCODE_MIPS16:
      opcode = mips16_nop_insn.insn_opcode;
      opcode = mips16_nop_insn.insn_opcode;
      size = 2;
      size = 2;
    }
      break;
  else
    case NOP_OPCODE_MIPS:
    {
    default:
      opcode = nop_insn.insn_opcode;
      opcode = nop_insn.insn_opcode;
      size = 4;
      size = 4;
 
      break;
    }
    }
 
 
  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
  excess = bytes % size;
  excess = bytes % size;
  if (excess != 0)
 
    {
  /* Handle the leading part if we're not inserting a whole number of
      /* If we're not inserting a whole number of instructions,
     instructions, and make it the end of the fixed part of the frag.
         pad the end of the fixed part of the frag with zeros.  */
     Try to fit in a short microMIPS NOP if applicable and possible,
      memset (p, 0, excess);
     and use zeroes otherwise.  */
      p += excess;
  gas_assert (excess < 4);
      fragp->fr_fix += excess;
      fragp->fr_fix += excess;
 
  switch (excess)
 
    {
 
    case 3:
 
      *p++ = '\0';
 
      /* Fall through.  */
 
    case 2:
 
      if (nop_opcode == NOP_OPCODE_MICROMIPS)
 
        {
 
          md_number_to_chars (p, micromips_nop16_insn.insn_opcode, 2);
 
          p += 2;
 
          break;
 
        }
 
      *p++ = '\0';
 
      /* Fall through.  */
 
    case 1:
 
      *p++ = '\0';
 
      /* Fall through.  */
 
    case 0:
 
      break;
    }
    }
 
 
  md_number_to_chars (p, opcode, size);
  md_number_to_chars (p, opcode, size);
  fragp->fr_var = size;
  fragp->fr_var = size;
}
}
Line 15613... Line 18960...
  { "4kem",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "4kem",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "4kep",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "4kep",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "4ksd",           MIPS_CPU_ASE_SMARTMIPS,   ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "4ksd",           MIPS_CPU_ASE_SMARTMIPS,   ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "m4k",            0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "m4k",            0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "m4kp",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "m4kp",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
 
  { "m14k",           MIPS_CPU_ASE_MCU,         ISA_MIPS32R2,   CPU_MIPS32R2 },
 
  { "m14kc",          MIPS_CPU_ASE_MCU,         ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kc",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kc",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kf2_1",        0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kf2_1",        0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kf",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kf",           0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kf1_1",        0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  { "24kf1_1",        0,                 ISA_MIPS32R2,   CPU_MIPS32R2 },
  /* Deprecated forms of the above.  */
  /* Deprecated forms of the above.  */
Line 15898... Line 19247...
 
 
  fprintf (stream, _("\
  fprintf (stream, _("\
-mips16                 generate mips16 instructions\n\
-mips16                 generate mips16 instructions\n\
-no-mips16              do not generate mips16 instructions\n"));
-no-mips16              do not generate mips16 instructions\n"));
  fprintf (stream, _("\
  fprintf (stream, _("\
 
-mmicromips             generate microMIPS instructions\n\
 
-mno-micromips          do not generate microMIPS instructions\n"));
 
  fprintf (stream, _("\
-msmartmips             generate smartmips instructions\n\
-msmartmips             generate smartmips instructions\n\
-mno-smartmips          do not generate smartmips instructions\n"));
-mno-smartmips          do not generate smartmips instructions\n"));
  fprintf (stream, _("\
  fprintf (stream, _("\
-mdsp                   generate DSP instructions\n\
-mdsp                   generate DSP instructions\n\
-mno-dsp                do not generate DSP instructions\n"));
-mno-dsp                do not generate DSP instructions\n"));
Line 15910... Line 19262...
-mno-dspr2              do not generate DSP R2 instructions\n"));
-mno-dspr2              do not generate DSP R2 instructions\n"));
  fprintf (stream, _("\
  fprintf (stream, _("\
-mmt                    generate MT instructions\n\
-mmt                    generate MT instructions\n\
-mno-mt                 do not generate MT instructions\n"));
-mno-mt                 do not generate MT instructions\n"));
  fprintf (stream, _("\
  fprintf (stream, _("\
 
-mmcu                   generate MCU instructions\n\
 
-mno-mcu                do not generate MCU instructions\n"));
 
  fprintf (stream, _("\
-mfix-loongson2f-jump   work around Loongson2F JUMP instructions\n\
-mfix-loongson2f-jump   work around Loongson2F JUMP instructions\n\
-mfix-loongson2f-nop    work around Loongson2F NOP errata\n\
-mfix-loongson2f-nop    work around Loongson2F NOP errata\n\
-mfix-vr4120            work around certain VR4120 errata\n\
-mfix-vr4120            work around certain VR4120 errata\n\
-mfix-vr4130            work around VR4130 mflo/mfhi errata\n\
-mfix-vr4130            work around VR4130 mflo/mfhi errata\n\
-mfix-24k               insert a nop after ERET and DERET instructions\n\
-mfix-24k               insert a nop after ERET and DERET instructions\n\

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.