+ If we have a small constant, and this is a reference to
+ an external symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_DISP)
+ addiu $tempreg,$tempreg,<constant>
+
+ If we have a large constant, and this is a reference to
+ an external symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_DISP)
+ lui $at,<hiconstant>
+ addiu $at,$at,<loconstant>
+ addu $tempreg,$tempreg,$at
+
+ (*) Other assemblers seem to prefer GOT_PAGE/GOT_OFST for
+ local symbols, even though it introduces an additional
+ instruction. */
+
+ if (offset_expr.X_add_number)
+ {
+ expr1.X_add_number = offset_expr.X_add_number;
+ offset_expr.X_add_number = 0;
+
+ relax_start (offset_expr.X_add_symbol);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+
+ if (expr1.X_add_number >= -0x8000
+ && expr1.X_add_number < 0x8000)
+ {
+ macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, tempreg, BFD_RELOC_LO16);
+ }
+ else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
+ {
+ unsigned int dreg;
+
+ /* If we are going to add in a base register, and the
+ target register and the base register are the same,
+ then we are using AT as a temporary register. Since
+ we want to load the constant into AT, we add our
+ current AT (from the global offset table) and the
+ register into the register now, and pretend we were
+ not using a base register. */
+ if (breg != op[0])
+ dreg = tempreg;
+ else
+ {
+ gas_assert (tempreg == AT);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ op[0], AT, breg);
+ dreg = op[0];
+ add_breg_early = 1;
+ }
+
+ load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ dreg, dreg, AT);
+
+ used_at = 1;
+ }
+ else
+ as_bad (_("PIC code offset overflow (max 32 signed bits)"));
+
+ relax_switch ();
+ offset_expr.X_add_number = expr1.X_add_number;
+
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+ if (add_breg_early)
+ {
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ op[0], tempreg, breg);
+ breg = 0;
+ tempreg = op[0];
+ }
+ relax_end ();
+ }
+ else if (breg == 0 && (call || tempreg == PIC_CALL_REG))
+ {
+ relax_start (offset_expr.X_add_symbol);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ BFD_RELOC_MIPS_CALL16, mips_gp_register);
+ relax_switch ();
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+ relax_end ();
+ }
+ else
+ {
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
+ }
+ }
+ else if (mips_big_got && !HAVE_NEWABI)
+ {
+ int gpdelay;
+ int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
+ int local_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
+
+ /* This is the large GOT case. If this is a reference to an
+ external symbol, and there is no constant, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ or for lca or if tempreg is PIC_CALL_REG
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
+ For a local symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ nop
+ addiu $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
+
+ If we have a small constant, and this is a reference to
+ an external symbol, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ nop
+ addiu $tempreg,$tempreg,<constant>
+ For a local symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ nop
+ addiu $tempreg,$tempreg,<constant> (BFD_RELOC_LO16)
+
+ If we have a large constant, and this is a reference to
+ an external symbol, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ lui $at,<hiconstant>
+ addiu $at,$at,<loconstant>
+ addu $tempreg,$tempreg,$at
+ For a local symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ lui $at,<hiconstant>
+ addiu $at,$at,<loconstant> (BFD_RELOC_LO16)
+ addu $tempreg,$tempreg,$at
+ */
+
+ expr1.X_add_number = offset_expr.X_add_number;
+ offset_expr.X_add_number = 0;
+ relax_start (offset_expr.X_add_symbol);
+ gpdelay = reg_needs_delay (mips_gp_register);
+ if (expr1.X_add_number == 0 && breg == 0
+ && (call || tempreg == PIC_CALL_REG))
+ {
+ lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+ }
+ macro_build (&offset_expr, "lui", LUI_FMT, tempreg, lui_reloc_type);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, mips_gp_register);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ tempreg, lw_reloc_type, tempreg);
+ if (expr1.X_add_number == 0)
+ {
+ if (breg != 0)
+ {
+ /* We're going to put in an addu instruction using
+ tempreg, so we may as well insert the nop right
+ now. */
+ load_delay_nop ();
+ }
+ }
+ else if (expr1.X_add_number >= -0x8000
+ && expr1.X_add_number < 0x8000)
+ {
+ load_delay_nop ();
+ macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, tempreg, BFD_RELOC_LO16);
+ }
+ else
+ {
+ unsigned int dreg;
+
+ /* If we are going to add in a base register, and the
+ target register and the base register are the same,
+ then we are using AT as a temporary register. Since
+ we want to load the constant into AT, we add our
+ current AT (from the global offset table) and the
+ register into the register now, and pretend we were
+ not using a base register. */
+ if (breg != op[0])
+ dreg = tempreg;
+ else
+ {
+ gas_assert (tempreg == AT);
+ load_delay_nop ();
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ op[0], AT, breg);
+ dreg = op[0];
+ }
+
+ load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
+
+ used_at = 1;
+ }
+ offset_expr.X_add_number = SEXT_16BIT (expr1.X_add_number);
+ relax_switch ();
+
+ if (gpdelay)
+ {
+ /* This is needed because this instruction uses $gp, but
+ the first instruction on the main stream does not. */
+ macro_build (NULL, "nop", "");
+ }
+
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ local_reloc_type, mips_gp_register);
+ if (expr1.X_add_number >= -0x8000
+ && expr1.X_add_number < 0x8000)
+ {
+ load_delay_nop ();
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, tempreg, BFD_RELOC_LO16);
+ /* FIXME: If add_number is 0, and there was no base
+ register, the external symbol case ended with a load,
+ so if the symbol turns out to not be external, and
+ the next instruction uses tempreg, an unnecessary nop
+ will be inserted. */
+ }
+ else
+ {
+ if (breg == op[0])
+ {
+ /* We must add in the base register now, as in the
+ external symbol case. */
+ gas_assert (tempreg == AT);
+ load_delay_nop ();
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ op[0], AT, breg);
+ tempreg = op[0];
+ /* We set breg to 0 because we have arranged to add
+ it in in both cases. */
+ breg = 0;
+ }
+
+ macro_build_lui (&expr1, AT);
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+ AT, AT, BFD_RELOC_LO16);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, AT);
+ used_at = 1;
+ }
+ relax_end ();
+ }
+ else if (mips_big_got && HAVE_NEWABI)
+ {
+ int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
+ int add_breg_early = 0;
+
+ /* This is the large GOT case. If this is a reference to an
+ external symbol, and there is no constant, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ add $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ or for lca or if tempreg is PIC_CALL_REG
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ add $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
+
+ If we have a small constant, and this is a reference to
+ an external symbol, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ add $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ addi $tempreg,$tempreg,<constant>
+
+ If we have a large constant, and this is a reference to
+ an external symbol, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ lui $at,<hiconstant>
+ addi $at,$at,<loconstant>
+ add $tempreg,$tempreg,$at
+
+ If we have NewABI, and we know it's a local symbol, we want
+ lw $reg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE)
+ addiu $reg,$reg,<sym> (BFD_RELOC_MIPS_GOT_OFST)
+ otherwise we have to resort to GOT_HI16/GOT_LO16. */
+
+ relax_start (offset_expr.X_add_symbol);
+
+ expr1.X_add_number = offset_expr.X_add_number;
+ offset_expr.X_add_number = 0;
+
+ if (expr1.X_add_number == 0 && breg == 0
+ && (call || tempreg == PIC_CALL_REG))
+ {
+ lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+ }
+ macro_build (&offset_expr, "lui", LUI_FMT, tempreg, lui_reloc_type);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, mips_gp_register);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ tempreg, lw_reloc_type, tempreg);
+
+ if (expr1.X_add_number == 0)
+ ;
+ else if (expr1.X_add_number >= -0x8000
+ && expr1.X_add_number < 0x8000)
+ {
+ macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, tempreg, BFD_RELOC_LO16);
+ }
+ else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
+ {
+ unsigned int dreg;
+
+ /* If we are going to add in a base register, and the
+ target register and the base register are the same,
+ then we are using AT as a temporary register. Since
+ we want to load the constant into AT, we add our
+ current AT (from the global offset table) and the
+ register into the register now, and pretend we were
+ not using a base register. */
+ if (breg != op[0])
+ dreg = tempreg;
+ else
+ {
+ gas_assert (tempreg == AT);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ op[0], AT, breg);
+ dreg = op[0];
+ add_breg_early = 1;
+ }
+
+ load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
+
+ used_at = 1;
+ }
+ else
+ as_bad (_("PIC code offset overflow (max 32 signed bits)"));
+
+ relax_switch ();
+ offset_expr.X_add_number = expr1.X_add_number;
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
+ BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
+ tempreg, BFD_RELOC_MIPS_GOT_OFST);
+ if (add_breg_early)
+ {
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+ op[0], tempreg, breg);
+ breg = 0;
+ tempreg = op[0];
+ }
+ relax_end ();
+ }
+ else
+ abort ();
+
+ if (breg != 0)
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", op[0], tempreg, breg);
+ break;
+
+ case M_MSGSND:
+ gas_assert (!mips_opts.micromips);
+ macro_build (NULL, "c2", "C", (op[0] << 16) | 0x01);
+ break;
+
+ case M_MSGLD:
+ gas_assert (!mips_opts.micromips);
+ macro_build (NULL, "c2", "C", 0x02);
+ break;
+
+ case M_MSGLD_T:
+ gas_assert (!mips_opts.micromips);
+ macro_build (NULL, "c2", "C", (op[0] << 16) | 0x02);
+ break;
+
+ case M_MSGWAIT:
+ gas_assert (!mips_opts.micromips);
+ macro_build (NULL, "c2", "C", 3);
+ break;
+
+ case M_MSGWAIT_T:
+ gas_assert (!mips_opts.micromips);
+ macro_build (NULL, "c2", "C", (op[0] << 16) | 0x03);
+ break;
+
+ case M_J_A:
+ /* The j instruction may not be used in PIC code, since it
+ requires an absolute address. We convert it to a b
+ instruction. */
+ if (mips_pic == NO_PIC)
+ macro_build (&offset_expr, "j", "a");
+ else
+ macro_build (&offset_expr, "b", "p");
+ break;
+
+ /* The jal instructions must be handled as macros because when
+ generating PIC code they expand to multi-instruction
+ sequences. Normally they are simple instructions. */
+ case M_JALS_1:
+ op[1] = op[0];
+ op[0] = RA;
+ /* Fall through. */
+ case M_JALS_2:
+ gas_assert (mips_opts.micromips);
+ if (mips_opts.insn32)
+ {
+ as_bad (_("opcode not supported in the `insn32' mode `%s'"), str);
+ break;
+ }
+ jals = 1;
+ goto jal;
+ case M_JAL_1:
+ op[1] = op[0];
+ op[0] = RA;
+ /* Fall through. */
+ case M_JAL_2:
+ jal:
+ if (mips_pic == NO_PIC)
+ {
+ s = jals ? "jalrs" : "jalr";
+ if (mips_opts.micromips
+ && !mips_opts.insn32
+ && op[0] == RA
+ && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
+ macro_build (NULL, s, "mj", op[1]);
+ else
+ macro_build (NULL, s, JALR_FMT, op[0], op[1]);
+ }
+ else
+ {
+ int cprestore = (mips_pic == SVR4_PIC && !HAVE_NEWABI
+ && mips_cprestore_offset >= 0);
+
+ if (op[1] != PIC_CALL_REG)
+ as_warn (_("MIPS PIC call to register other than $25"));
+
+ s = ((mips_opts.micromips
+ && !mips_opts.insn32
+ && (!mips_opts.noreorder || cprestore))
+ ? "jalrs" : "jalr");
+ if (mips_opts.micromips
+ && !mips_opts.insn32
+ && op[0] == RA
+ && !(history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT))
+ macro_build (NULL, s, "mj", op[1]);
+ else
+ macro_build (NULL, s, JALR_FMT, op[0], op[1]);
+ if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
+ {
+ if (mips_cprestore_offset < 0)
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
+ else
+ {
+ if (!mips_frame_reg_valid)
+ {
+ as_warn (_("no .frame pseudo-op used in PIC code"));
+ /* Quiet this warning. */
+ mips_frame_reg_valid = 1;
+ }
+ if (!mips_cprestore_valid)
+ {
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
+ /* Quiet this warning. */
+ mips_cprestore_valid = 1;
+ }
+ if (mips_opts.noreorder)
+ macro_build (NULL, "nop", "");
+ expr1.X_add_number = mips_cprestore_offset;
+ macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
+ mips_gp_register,
+ mips_frame_reg,
+ HAVE_64BIT_ADDRESSES);
+ }
+ }
+ }
+
+ break;
+
+ case M_JALS_A:
+ gas_assert (mips_opts.micromips);
+ if (mips_opts.insn32)
+ {
+ as_bad (_("opcode not supported in the `insn32' mode `%s'"), str);
+ break;
+ }
+ jals = 1;
+ /* Fall through. */
+ case M_JAL_A:
+ if (mips_pic == NO_PIC)
+ macro_build (&offset_expr, jals ? "jals" : "jal", "a");
+ else if (mips_pic == SVR4_PIC)
+ {
+ /* If this is a reference to an external symbol, and we are
+ using a small GOT, we want
+ lw $25,<sym>($gp) (BFD_RELOC_MIPS_CALL16)
+ nop
+ jalr $ra,$25
+ nop
+ lw $gp,cprestore($sp)
+ The cprestore value is set using the .cprestore
+ pseudo-op. If we are using a big GOT, we want
+ lui $25,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ addu $25,$25,$gp
+ lw $25,<sym>($25) (BFD_RELOC_MIPS_CALL_LO16)
+ nop
+ jalr $ra,$25
+ nop
+ lw $gp,cprestore($sp)
+ If the symbol is not external, we want
+ lw $25,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ nop
+ addiu $25,$25,<sym> (BFD_RELOC_LO16)
+ jalr $ra,$25
+ nop
+ lw $gp,cprestore($sp)
+
+ For NewABI, we use the same CALL16 or CALL_HI16/CALL_LO16
+ sequences above, minus nops, unless the symbol is local,
+ which enables us to use GOT_PAGE/GOT_OFST (big got) or
+ GOT_DISP. */
+ if (HAVE_NEWABI)
+ {
+ if (!mips_big_got)
+ {
+ relax_start (offset_expr.X_add_symbol);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
+ mips_gp_register);
+ relax_switch ();
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_GOT_DISP,
+ mips_gp_register);
+ relax_end ();
+ }
+ else
+ {
+ relax_start (offset_expr.X_add_symbol);
+ macro_build (&offset_expr, "lui", LUI_FMT, PIC_CALL_REG,
+ BFD_RELOC_MIPS_CALL_HI16);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
+ PIC_CALL_REG, mips_gp_register);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
+ PIC_CALL_REG);
+ relax_switch ();
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_GOT_PAGE,
+ mips_gp_register);
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+ PIC_CALL_REG, PIC_CALL_REG,
+ BFD_RELOC_MIPS_GOT_OFST);
+ relax_end ();
+ }
+
+ macro_build_jalr (&offset_expr, 0);
+ }
+ else
+ {
+ relax_start (offset_expr.X_add_symbol);
+ if (!mips_big_got)
+ {
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
+ mips_gp_register);
+ load_delay_nop ();
+ relax_switch ();
+ }
+ else
+ {
+ int gpdelay;
+
+ gpdelay = reg_needs_delay (mips_gp_register);
+ macro_build (&offset_expr, "lui", LUI_FMT, PIC_CALL_REG,
+ BFD_RELOC_MIPS_CALL_HI16);
+ macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
+ PIC_CALL_REG, mips_gp_register);
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
+ PIC_CALL_REG);
+ load_delay_nop ();
+ relax_switch ();
+ if (gpdelay)
+ macro_build (NULL, "nop", "");
+ }
+ macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ PIC_CALL_REG, BFD_RELOC_MIPS_GOT16,
+ mips_gp_register);
+ load_delay_nop ();
+ macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+ PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
+ relax_end ();
+ macro_build_jalr (&offset_expr, mips_cprestore_offset >= 0);
+
+ if (mips_cprestore_offset < 0)
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
+ else
+ {
+ if (!mips_frame_reg_valid)
+ {
+ as_warn (_("no .frame pseudo-op used in PIC code"));
+ /* Quiet this warning. */
+ mips_frame_reg_valid = 1;
+ }
+ if (!mips_cprestore_valid)
+ {
+ as_warn (_("no .cprestore pseudo-op used in PIC code"));
+ /* Quiet this warning. */
+ mips_cprestore_valid = 1;
+ }
+ if (mips_opts.noreorder)
+ macro_build (NULL, "nop", "");
+ expr1.X_add_number = mips_cprestore_offset;
+ macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
+ mips_gp_register,
+ mips_frame_reg,
+ HAVE_64BIT_ADDRESSES);
+ }
+ }
+ }
+ else if (mips_pic == VXWORKS_PIC)
+ as_bad (_("non-PIC jump used in PIC library"));
+ else
+ abort ();
+
+ break;
+
+ case M_LBUE_AB:
+ s = "lbue";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LHUE_AB:
+ s = "lhue";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LBE_AB:
+ s = "lbe";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LHE_AB:
+ s = "lhe";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LLE_AB:
+ s = "lle";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LWE_AB:
+ s = "lwe";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LWLE_AB:
+ s = "lwle";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_LWRE_AB:
+ s = "lwre";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SBE_AB:
+ s = "sbe";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SCE_AB:
+ s = "sce";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SHE_AB:
+ s = "she";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SWE_AB:
+ s = "swe";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SWLE_AB:
+ s = "swle";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SWRE_AB:
+ s = "swre";
+ fmt = "t,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_ACLR_AB:
+ s = "aclr";
+ fmt = "\\,~(b)";
+ offbits = 12;
+ goto ld_st;
+ case M_ASET_AB:
+ s = "aset";
+ fmt = "\\,~(b)";
+ offbits = 12;
+ goto ld_st;
+ case M_LB_AB:
+ s = "lb";
+ fmt = "t,o(b)";
+ goto ld;
+ case M_LBU_AB:
+ s = "lbu";
+ fmt = "t,o(b)";
+ goto ld;
+ case M_LH_AB:
+ s = "lh";
+ fmt = "t,o(b)";
+ goto ld;
+ case M_LHU_AB:
+ s = "lhu";
+ fmt = "t,o(b)";
+ goto ld;
+ case M_LW_AB:
+ s = "lw";
+ fmt = "t,o(b)";
+ goto ld;
+ case M_LWC0_AB:
+ gas_assert (!mips_opts.micromips);
+ s = "lwc0";
+ fmt = "E,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LWC1_AB:
+ s = "lwc1";
+ fmt = "T,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LWC2_AB:
+ s = "lwc2";
+ fmt = COP12_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LWC3_AB:
+ gas_assert (!mips_opts.micromips);
+ s = "lwc3";
+ fmt = "E,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LWL_AB:
+ s = "lwl";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_LWR_AB:
+ s = "lwr";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_LDC1_AB:
+ s = "ldc1";
+ fmt = "T,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LDC2_AB:
+ s = "ldc2";
+ fmt = COP12_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LQC2_AB:
+ s = "lqc2";
+ fmt = "+7,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LDC3_AB:
+ s = "ldc3";
+ fmt = "E,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_LDL_AB:
+ s = "ldl";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_LDR_AB:
+ s = "ldr";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_LL_AB:
+ s = "ll";
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
+ goto ld;
+ case M_LLD_AB:
+ s = "lld";
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
+ goto ld;
+ case M_LWU_AB:
+ s = "lwu";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld;
+ case M_LWP_AB:
+ gas_assert (mips_opts.micromips);
+ s = "lwp";
+ fmt = "t,~(b)";
+ offbits = 12;
+ lp = 1;
+ goto ld;
+ case M_LDP_AB:
+ gas_assert (mips_opts.micromips);
+ s = "ldp";
+ fmt = "t,~(b)";
+ offbits = 12;
+ lp = 1;
+ goto ld;
+ case M_LWM_AB:
+ gas_assert (mips_opts.micromips);
+ s = "lwm";
+ fmt = "n,~(b)";
+ offbits = 12;
+ goto ld_st;
+ case M_LDM_AB:
+ gas_assert (mips_opts.micromips);
+ s = "ldm";
+ fmt = "n,~(b)";
+ offbits = 12;
+ goto ld_st;
+
+ ld:
+ /* We don't want to use $0 as tempreg. */
+ if (op[2] == op[0] + lp || op[0] + lp == ZERO)
+ goto ld_st;
+ else
+ tempreg = op[0] + lp;
+ goto ld_noat;
+
+ case M_SB_AB:
+ s = "sb";
+ fmt = "t,o(b)";
+ goto ld_st;
+ case M_SH_AB:
+ s = "sh";
+ fmt = "t,o(b)";
+ goto ld_st;
+ case M_SW_AB:
+ s = "sw";
+ fmt = "t,o(b)";
+ goto ld_st;
+ case M_SWC0_AB:
+ gas_assert (!mips_opts.micromips);
+ s = "swc0";
+ fmt = "E,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SWC1_AB:
+ s = "swc1";
+ fmt = "T,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SWC2_AB:
+ s = "swc2";
+ fmt = COP12_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SWC3_AB:
+ gas_assert (!mips_opts.micromips);
+ s = "swc3";
+ fmt = "E,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SWL_AB:
+ s = "swl";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_SWR_AB:
+ s = "swr";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_SC_AB:
+ s = "sc";
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
+ goto ld_st;
+ case M_SCD_AB:
+ s = "scd";
+ fmt = LL_SC_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
+ goto ld_st;
+ case M_CACHE_AB:
+ s = "cache";
+ fmt = (mips_opts.micromips ? "k,~(b)"
+ : ISA_IS_R6 (mips_opts.isa) ? "k,+j(b)"
+ : "k,o(b)");
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
+ goto ld_st;
+ case M_CACHEE_AB:
+ s = "cachee";
+ fmt = "k,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_PREF_AB:
+ s = "pref";
+ fmt = (mips_opts.micromips ? "k,~(b)"
+ : ISA_IS_R6 (mips_opts.isa) ? "k,+j(b)"
+ : "k,o(b)");
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 9
+ : 16);
+ goto ld_st;
+ case M_PREFE_AB:
+ s = "prefe";
+ fmt = "k,+j(b)";
+ offbits = 9;
+ goto ld_st;
+ case M_SDC1_AB:
+ s = "sdc1";
+ fmt = "T,o(b)";
+ coproc = 1;
+ /* Itbl support may require additional care here. */
+ goto ld_st;
+ case M_SDC2_AB:
+ s = "sdc2";
+ fmt = COP12_FMT;
+ offbits = (mips_opts.micromips ? 12
+ : ISA_IS_R6 (mips_opts.isa) ? 11
+ : 16);
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SQC2_AB:
+ s = "sqc2";
+ fmt = "+7,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SDC3_AB:
+ gas_assert (!mips_opts.micromips);
+ s = "sdc3";
+ fmt = "E,o(b)";
+ /* Itbl support may require additional care here. */
+ coproc = 1;
+ goto ld_st;
+ case M_SDL_AB:
+ s = "sdl";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_SDR_AB:
+ s = "sdr";
+ fmt = MEM12_FMT;
+ offbits = (mips_opts.micromips ? 12 : 16);
+ goto ld_st;
+ case M_SWP_AB:
+ gas_assert (mips_opts.micromips);
+ s = "swp";
+ fmt = "t,~(b)";
+ offbits = 12;
+ goto ld_st;
+ case M_SDP_AB:
+ gas_assert (mips_opts.micromips);
+ s = "sdp";
+ fmt = "t,~(b)";
+ offbits = 12;
+ goto ld_st;
+ case M_SWM_AB:
+ gas_assert (mips_opts.micromips);
+ s = "swm";
+ fmt = "n,~(b)";
+ offbits = 12;
+ goto ld_st;
+ case M_SDM_AB:
+ gas_assert (mips_opts.micromips);
+ s = "sdm";
+ fmt = "n,~(b)";
+ offbits = 12;