This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Remove o(b) MIPS macros and use A(b) instead


Many MIPS macros come in both o(b) and A(b) forms.  This patch:

- removes the o(b) ones
- generalises A to allow relocation operators
- generalises the macro code to handle the new form of A

Normally I'm very uneasy about changes to the macro code.  Tinkering
with them isn't likely to have much practical benefit and can break
corner cases in unexpected ways.  I'm making an exception here though
because I think reducing the number of cases improves maintainability.
I hope that doesn't turn out to be the wrong decision.

One reason I decided to go ahead is that micromips.d was requiring
incorrect output for LD and SD.  E.g. for:

	ld	$3, 32767($4)

it wanted:

[ 0-9a-f]+:	fc64 7fff 	lw	v1,32767\(a0\)
[ 0-9a-f]+:	fc84 8003 	lw	a0,-32765\(a0\)

where the second offset is wrong.  Years ago, Maciej posted a patch
to handle the general case where addr+4 has a different high part
from addr, even for symbolic addresses.  I objected because I thought
such cases were invalid and that we were compatible with traditional
behaviour:

   http://article.gmane.org/gmane.comp.gnu.binutils/20413

I still think that's true, which is why I'm not touching the symbolic case.
However, I hadn't noticed that instructions like those above had been
included in the micromips test.  It seems silly to require something
that clearly wouldn't work, and the changes to handle relocation
operators for A(b) happened to fix them in passing, so I updated
them rather than removed them.

And since I was having to rewrite that part of the code anyway, I thought
I might as well as handle the LD case in which the first destination
register is the same as the base.  As above, I don't think either of
these changes are likely to have any practical benefit.

A side-effect of the changes is that we generate better code in some cases.
E.g. if the offset field is smaller than 16 bits, we would often use
sequences like:

	li	$1,-4096
	addu	$1,$1,base

rather than:

	addiu	$1,base,-4096

so again I decided to update the tests rather than require the old
behaviour.  Most of the testsuite changes are of this form.

FWIW, the original motivation for doing this was that I wanted to
separate out the operand types that are used to communicate between
mips_ip() and macro() from those that actually describe opcode fields.
Now "o" is only used for real instructions.

Applied.

Richard


include/opcode/
	* mips.h (M_ACLR_OB, M_ASET_OB, M_CACHE_OB, M_CACHEE_OB, M_L_DOB)
	(M_LB_A, M_LBE_OB, M_LBU_A, M_LBUE_OB, M_LD_A, M_LD_OB, M_LDC2_OB)
	(M_LDL_OB, M_LDM_OB, M_LDP_OB, M_LDR_OB, M_LH_A, M_LHE_OB, M_LHU_A)
	(M_LHUE_OB, M_LL_OB, M_LLD_OB, M_LLE_OB, M_LS_A, M_LW_A, M_LWE_OB)
	(M_LWC0_A, M_LWC1_A, M_LWC2_A, M_LWC2_OB, M_LWC3_A, M_LWL_A, M_LWL_OB)
	(M_LWLE_OB, M_LWM_OB, M_LWP_OB, M_LWR_A, M_LWR_OB, M_LWRE_OB, M_LWU_OB)
	(M_PREF_OB, M_PREFE_OB, M_S_DOB, M_SAA_OB, M_SAAD_OB, M_SC_OB)
	(M_SCD_OB, M_SCE_OB, M_SD_A, M_SD_OB, M_SDC2_OB, M_SDL_OB, M_SDM_OB)
	(M_SDP_OB, M_SDR_OB, M_SB_A, M_SBE_OB, M_SH_A, M_SHE_OB, M_SW_A)
	(M_SWE_OB, M_SWC0_A, M_SWC1_A, M_SWC2_A, M_SWC2_OB, M_SWC3_A, M_SWL_A)
	(M_SWL_OB, M_SWLE_OB, M_SWM_OB, M_SWP_OB, M_SWR_A, M_SWR_OB, M_SWRE_OB)
	(M_ULD, M_ULH, M_ULHU, M_ULW, M_USH, M_USW, M_USD): Delete.
	(M_ULD_A, M_ULH_A, M_ULHU_A, M_ULW_A, M_USH_A, M_USW_A, M_USD_A):
	Rename to...
	(M_ULD_AB, M_ULH_AB, M_ULHU_AB, M_ULW_AB, M_USH_AB, M_USW_AB)
	(M_USD_AB): ...these.

opcodes/
	* mips-opc.c (mips_builtin_opcodes): Remove o(b) macros.  Move LD
	and SD A(B) macros up.
	* micromips-opc.c (micromips_opcodes): Likewise.

gas/
	* config/tc-mips.c (gprel16_reloc_p): New function.
	(macro_read_relocs): Assume BFD_RELOC_LO16 if all relocs are
	BFD_RELOC_UNUSED.
	(offset_high_part, small_offset_p): New functions.
	(nacro): Use them.  Remove *_OB and *_DOB cases.  For single-
	register load and store macros, handle the 16-bit offset case first.
	If a 16-bit offset is not suitable for the instruction we're
	generating, load it into the temporary register using
	ADDRESS_ADDI_INSN.  Make the M_LI_DD code fall through into the
	M_L_DAB code once the address has been constructed.  For double load
	and store macros, again handle the 16-bit offset case first.
	If the second register cannot be accessed from the same high
	part as the first, load it into AT using ADDRESS_ADDI_INSN.
	Fix the handling of LD in cases where the first register is the
	same as the base.  Also handle the case where the offset is
	not 16 bits and the second register cannot be accessed from the
	same high part as the first.  For unaligned loads and stores,
	fuse the offbits == 12 and old "ab" handling.  Apply this handling
	whenever the second offset needs a different high part from the first.
	Construct the offset using ADDRESS_ADDI_INSN where possible,
	for offbits == 16 as well as offbits == 12.  Use offset_reloc
	when constructing the individual loads and stores.
	(mips_ip): Set up imm_expr, imm2_expr, offset_expr, imm_reloc
	and offset_reloc before matching against a particular opcode.
	Handle elided 'A' constants.  Allow 'A' constants to use
	relocation operators.

gas/testsuite/
	* gas/mips/ldstla-32.d: Avoid "lui at,0x0" sequences for
	truncated constants.
	* gas/mips/ldstla-32-shared.d: Likewise.
	* gas/mips/mcu.d: Use ADDIU in preference to LI+ADDU when adding
	16-bit constants to the base.
	* gas/mips/micromips@mcu.d: Likewise.
	* gas/mips/micromips@cache.d: Likewise.
	* gas/mips/micromips@pref.d: Likewise.
	* gas/mips/micromips.d, gas/mips/micromips-insn32.d,
	gas/mips/micromips-noinsn32.d, gas/mips/micromips-trap.d: Likewise.
	Allow the full 16-bit offset range to be used for SB, LB and LBU in
	USH and ULH sequences.  Fix the expected output for LD and SD when
	the two LW and SW offsets need different high parts.
	* gas/mips/eva.s: Test PREFE with relocation operators.
	* gas/mips/eva.d: Use ADDIU in preference to LI+ADDU for 16-bit
	constants.  Update after eva.s change.
	* gas/mips/micromips@eva.d: Likewise.
	* gas/mips/ld-reloc.s, gas/mips/ld-reloc.d, gas/mips/l_d-reloc.s,
	gas/mips/l_d-reloc.d, gas/mips/ulw-reloc.s, gas/mips/ulw-reloc.d,
	gas/mips/micromips@ulw-reloc.d, gas/mips/ulh-reloc.s,
	gas/mips/ulh-reloc.d: New tests.
	* gas/mips/mips.exp: Run them.

Index: include/opcode/mips.h
===================================================================
--- include/opcode/mips.h	2013-07-07 11:52:40.403442316 +0100
+++ include/opcode/mips.h	2013-07-07 11:52:43.106465765 +0100
@@ -947,8 +947,8 @@ opcode_is_member (const struct mips_opco
 /* This is a list of macro expanded instructions.
 
    _I appended means immediate
-   _A appended means address
-   _AB appended means address with base register
+   _A appended means target address of a jump
+   _AB appended means address with (possibly zero) base register
    _D appended means 64 bit floating point constant
    _S appended means 32 bit floating point constant.  */
 
@@ -956,12 +956,10 @@ enum
 {
   M_ABS,
   M_ACLR_AB,
-  M_ACLR_OB,
   M_ADD_I,
   M_ADDU_I,
   M_AND_I,
   M_ASET_AB,
-  M_ASET_OB,
   M_BALIGN,
   M_BC1FL,
   M_BC1TL,
@@ -1018,9 +1016,7 @@ enum
   M_BNE_I,
   M_BNEL_I,
   M_CACHE_AB,
-  M_CACHE_OB,
   M_CACHEE_AB,
-  M_CACHEE_OB,
   M_DABS,
   M_DADD_I,
   M_DADDU_I,
@@ -1059,41 +1055,25 @@ enum
   M_JALS_A,
   M_JRADDIUSP,
   M_JRC,
-  M_L_DOB,
   M_L_DAB,
   M_LA_AB,
-  M_LB_A,
   M_LB_AB,
-  M_LBE_OB,
   M_LBE_AB,
-  M_LBU_A,
   M_LBU_AB,
-  M_LBUE_OB,
   M_LBUE_AB,
   M_LCA_AB,
-  M_LD_A,
-  M_LD_OB,
   M_LD_AB,
   M_LDC1_AB,
   M_LDC2_AB,
-  M_LDC2_OB,
   M_LQC2_AB,
   M_LDC3_AB,
   M_LDL_AB,
-  M_LDL_OB,
   M_LDM_AB,
-  M_LDM_OB,
   M_LDP_AB,
-  M_LDP_OB,
   M_LDR_AB,
-  M_LDR_OB,
-  M_LH_A,
   M_LH_AB,
-  M_LHE_OB,
   M_LHE_AB,
-  M_LHU_A,
   M_LHU_AB,
-  M_LHUE_OB,
   M_LHUE_AB,
   M_LI,
   M_LI_D,
@@ -1101,42 +1081,22 @@ enum
   M_LI_S,
   M_LI_SS,
   M_LL_AB,
-  M_LL_OB,
   M_LLD_AB,
-  M_LLD_OB,
   M_LLE_AB,
-  M_LLE_OB,
   M_LQ_AB,
-  M_LS_A,
-  M_LW_A,
   M_LW_AB,
-  M_LWE_OB,
   M_LWE_AB,
-  M_LWC0_A,
   M_LWC0_AB,
-  M_LWC1_A,
   M_LWC1_AB,
-  M_LWC2_A,
   M_LWC2_AB,
-  M_LWC2_OB,
-  M_LWC3_A,
   M_LWC3_AB,
-  M_LWL_A,
   M_LWL_AB,
-  M_LWL_OB,
   M_LWLE_AB,
-  M_LWLE_OB,
   M_LWM_AB,
-  M_LWM_OB,
   M_LWP_AB,
-  M_LWP_OB,
-  M_LWR_A,
   M_LWR_AB,
-  M_LWR_OB,
   M_LWRE_AB,
-  M_LWRE_OB,
   M_LWU_AB,
-  M_LWU_OB,
   M_MSGSND,
   M_MSGLD,
   M_MSGLD_T,
@@ -1153,9 +1113,7 @@ enum
   M_NOR_I,
   M_OR_I,
   M_PREF_AB,
-  M_PREF_OB,
   M_PREFE_AB,
-  M_PREFE_OB,
   M_REM_3,
   M_REM_3I,
   M_REMU_3,
@@ -1169,35 +1127,22 @@ enum
   M_DROR_I,
   M_ROR_I,
   M_S_DA,
-  M_S_DOB,
   M_S_DAB,
   M_S_S,
   M_SAA_AB,
-  M_SAA_OB,
   M_SAAD_AB,
-  M_SAAD_OB,
   M_SC_AB,
-  M_SC_OB,
   M_SCD_AB,
-  M_SCD_OB,
   M_SCE_AB,
-  M_SCE_OB,
-  M_SD_A,
-  M_SD_OB,
   M_SD_AB,
   M_SDC1_AB,
   M_SDC2_AB,
-  M_SDC2_OB,
   M_SQC2_AB,
   M_SDC3_AB,
   M_SDL_AB,
-  M_SDL_OB,
   M_SDM_AB,
-  M_SDM_OB,
   M_SDP_AB,
-  M_SDP_OB,
   M_SDR_AB,
-  M_SDR_OB,
   M_SEQ,
   M_SEQ_I,
   M_SGE,
@@ -1216,42 +1161,23 @@ enum
   M_SLTU_I,
   M_SNE,
   M_SNE_I,
-  M_SB_A,
   M_SB_AB,
-  M_SBE_OB,
   M_SBE_AB,
-  M_SH_A,
   M_SH_AB,
-  M_SHE_OB,
   M_SHE_AB,
   M_SQ_AB,
-  M_SW_A,
   M_SW_AB,
-  M_SWE_OB,
   M_SWE_AB,
-  M_SWC0_A,
   M_SWC0_AB,
-  M_SWC1_A,
   M_SWC1_AB,
-  M_SWC2_A,
   M_SWC2_AB,
-  M_SWC2_OB,
-  M_SWC3_A,
   M_SWC3_AB,
-  M_SWL_A,
   M_SWL_AB,
-  M_SWL_OB,
   M_SWLE_AB,
-  M_SWLE_OB,
   M_SWM_AB,
-  M_SWM_OB,
   M_SWP_AB,
-  M_SWP_OB,
-  M_SWR_A,
   M_SWR_AB,
-  M_SWR_OB,
   M_SWRE_AB,
-  M_SWRE_OB,
   M_SUB_I,
   M_SUBU_I,
   M_SUBU_I_2,
@@ -1263,20 +1189,13 @@ enum
   M_TNE_I,
   M_TRUNCWD,
   M_TRUNCWS,
-  M_ULD,
-  M_ULD_A,
-  M_ULH,
-  M_ULH_A,
-  M_ULHU,
-  M_ULHU_A,
-  M_ULW,
-  M_ULW_A,
-  M_USH,
-  M_USH_A,
-  M_USW,
-  M_USW_A,
-  M_USD,
-  M_USD_A,
+  M_ULD_AB,
+  M_ULH_AB,
+  M_ULHU_AB,
+  M_ULW_AB,
+  M_USH_AB,
+  M_USW_AB,
+  M_USD_AB,
   M_XOR_I,
   M_COP0,
   M_COP1,
Index: opcodes/micromips-opc.c
===================================================================
--- opcodes/micromips-opc.c	2013-07-07 11:52:40.403442316 +0100
+++ opcodes/micromips-opc.c	2013-07-07 11:52:43.108465783 +0100
@@ -127,7 +127,6 @@ const struct mips_opcode micromips_opcod
    instruction name anyhow.  */
 /* name,    args,	match,      mask,	pinfo,			pinfo2,		membership,	[ase],	[exclusions] */
 {"pref",    "k,~(b)",	0x60002000, 0xfc00f000,	RD_b,			0,		I1	},
-{"pref",    "k,o(b)",	0,    (int) M_PREF_OB,	INSN_MACRO,		0,		I1	},
 {"pref",    "k,A(b)",	0,    (int) M_PREF_AB,	INSN_MACRO,		0,		I1	},
 {"prefx",   "h,t(b)",	0x540001a0, 0xfc0007ff,	RD_b|RD_t|FP_S,		0,		I1	},
 {"nop",     "",		    0x0c00,     0xffff,	0,			INSN2_ALIAS,	I1	},
@@ -160,7 +159,6 @@ const struct mips_opcode micromips_opcod
 {"abs.s",   "T,V",	0x5400037b, 0xfc00ffff,	WR_T|RD_S|FP_S,		0,		I1	},
 {"abs.ps",  "T,V",	0x5400437b, 0xfc00ffff,	WR_T|RD_S|FP_D,		0,		I1	},
 {"aclr",    "\\,~(b)",	0x2000b000, 0xff00f000,	SM|RD_b|NODS,		0,		0,	MC	},
-{"aclr",    "\\,o(b)",	0,    (int) M_ACLR_OB,	INSN_MACRO,		0,		0,	MC	},
 {"aclr",    "\\,A(b)",	0,    (int) M_ACLR_AB,	INSN_MACRO,		0,		0,	MC	},
 {"add",     "d,v,t",	0x00000110, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
 {"add",     "t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		0,		I1	},
@@ -195,7 +193,6 @@ const struct mips_opcode micromips_opcod
 {"andi",    "md,mc,mC",	    0x2c00,     0xfc00,	0,			WR_md|RD_mc,	I1	},
 {"andi",    "t,r,i",	0xd0000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
 {"aset",    "\\,~(b)",	0x20003000, 0xff00f000,	SM|RD_b|NODS,		0,		0,	MC	},
-{"aset",    "\\,o(b)",	0,    (int) M_ASET_OB,	INSN_MACRO,		0,		0,	MC	},
 {"aset",    "\\,A(b)",	0,    (int) M_ASET_AB,	INSN_MACRO,		0,		0,	MC	},
 /* b is at the top of the table.  */
 /* bal is at the top of the table.  */
@@ -383,7 +380,6 @@ const struct mips_opcode micromips_opcod
 {"c.ngt.ps", "S,T",	0x54000bfc, 0xfc00ffff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
 {"c.ngt.ps", "M,S,T",	0x54000bfc, 0xfc001fff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
 {"cache",   "k,~(b)",	0x20006000, 0xfc00f000,	RD_b,			0,		I1	},
-{"cache",   "k,o(b)",	0,    (int) M_CACHE_OB,	INSN_MACRO,		0,		I1	},
 {"cache",   "k,A(b)",	0,    (int) M_CACHE_AB,	INSN_MACRO,		0,		I1	},
 {"ceil.l.d", "T,S",	0x5400533b, 0xfc00ffff,	WR_T|RD_S|FP_D,		0,		I1	},
 {"ceil.l.s", "T,S",	0x5400133b, 0xfc00ffff,	WR_T|RD_S|FP_S|FP_D,	0,		I1	},
@@ -596,29 +592,23 @@ const struct mips_opcode micromips_opcod
 {"lbu",     "t,A(b)",	0,    (int) M_LBU_AB,	INSN_MACRO,		0,		I1	},
 {"lca",     "t,A(b)",	0,    (int) M_LCA_AB,	INSN_MACRO,		0,		I1	},
 /* The macro has to be first to handle o32 correctly.  */
-{"ld",      "t,o(b)",	0,    (int) M_LD_OB,	INSN_MACRO,		0,		I1	},
-{"ld",      "t,o(b)",	0xdc000000, 0xfc000000,	RD_b|WR_t,		0,		I3	},
 {"ld",      "t,A(b)",	0,    (int) M_LD_AB,	INSN_MACRO,		0,		I1	},
+{"ld",      "t,o(b)",	0xdc000000, 0xfc000000,	RD_b|WR_t,		0,		I3	},
 {"ldc1",    "T,o(b)",	0xbc000000, 0xfc000000,	RD_b|WR_T|FP_D,		0,		I1	},
 {"ldc1",    "E,o(b)",	0xbc000000, 0xfc000000,	RD_b|WR_T|FP_D,		0,		I1	},
 {"ldc1",    "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"ldc1",    "E,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"ldc2",    "E,~(b)",	0x20002000, 0xfc00f000,	RD_b|WR_CC,		0,		I1	},
-{"ldc2",    "E,o(b)",	0,    (int) M_LDC2_OB,	INSN_MACRO,		0,		I1	},
 {"ldc2",    "E,A(b)",	0,    (int) M_LDC2_AB,	INSN_MACRO,		0,		I1	},
 {"l.d",     "T,o(b)",	0xbc000000, 0xfc000000,	RD_b|WR_T|FP_D,	0,		I1	}, /* ldc1 */
 {"l.d",     "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"ldl",     "t,~(b)",	0x60004000, 0xfc00f000,	WR_t|RD_b,		0,		I3	},
-{"ldl",     "t,o(b)",	0,    (int) M_LDL_OB,	INSN_MACRO,		0,		I3	},
 {"ldl",     "t,A(b)",	0,    (int) M_LDL_AB,	INSN_MACRO,		0,		I3	},
 {"ldm",     "n,~(b)",	0x20007000, 0xfc00f000,	RD_b,			0,		I3	},
-{"ldm",     "n,o(b)",	0,    (int) M_LDM_OB,	INSN_MACRO,		0,		I3	},
 {"ldm",     "n,A(b)",	0,    (int) M_LDM_AB,	INSN_MACRO,		0,		I3	},
 {"ldp",     "t,~(b)",	0x20004000, 0xfc00f000,	RD_b|WR_t,		0,		I3	},
-{"ldp",     "t,o(b)",	0,    (int) M_LDP_OB,	INSN_MACRO,		0,		I3	},
 {"ldp",     "t,A(b)",	0,    (int) M_LDP_AB,	INSN_MACRO,		0,		I3	},
 {"ldr",     "t,~(b)",	0x60005000, 0xfc00f000,	WR_t|RD_b,		0,		I3	},
-{"ldr",     "t,o(b)",	0,    (int) M_LDR_OB,	INSN_MACRO,		0,		I3	},
 {"ldr",     "t,A(b)",	0,    (int) M_LDR_AB,	INSN_MACRO,		0,		I3	},
 {"ldxc1",   "D,t(b)",	0x540000c8, 0xfc0007ff,	WR_D|RD_t|RD_b|FP_D,	0,		I1	},
 {"lh",      "t,o(b)",	0x3c000000, 0xfc000000,	RD_b|WR_t,		0,		I1	},
@@ -632,10 +622,8 @@ const struct mips_opcode micromips_opcod
 {"li.s",    "t,f",	0,    (int) M_LI_S,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"li.s",    "T,l",	0,    (int) M_LI_SS,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"ll",      "t,~(b)",	0x60003000, 0xfc00f000,	RD_b|WR_t,		0,		I1	},
-{"ll",      "t,o(b)",	0,    (int) M_LL_OB,	INSN_MACRO,		0,		I1	},
 {"ll",      "t,A(b)",	0,    (int) M_LL_AB,	INSN_MACRO,		0,		I1	},
 {"lld",     "t,~(b)",	0x60007000, 0xfc00f000,	RD_b|WR_t,		0,		I3	},
-{"lld",     "t,o(b)",	0,    (int) M_LLD_OB,	INSN_MACRO,		0,		I3	},
 {"lld",     "t,A(b)",	0,    (int) M_LLD_AB,	INSN_MACRO,		0,		I3	},
 {"lui",     "s,u",	0x41a00000, 0xffe00000,	WR_s,			0,		I1	},
 {"luxc1",   "D,t(b)",	0x54000148, 0xfc0007ff,	WR_D|RD_t|RD_b|FP_D,	0,		I1	},
@@ -649,32 +637,24 @@ const struct mips_opcode micromips_opcod
 {"lwc1",    "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"lwc1",    "E,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"lwc2",    "E,~(b)",	0x20000000, 0xfc00f000,	RD_b|WR_CC,		0,		I1	},
-{"lwc2",    "E,o(b)",	0,    (int) M_LWC2_OB,	INSN_MACRO,		0,		I1	},
 {"lwc2",    "E,A(b)",	0,    (int) M_LWC2_AB,	INSN_MACRO,		0,		I1	},
 {"l.s",     "T,o(b)",	0x9c000000, 0xfc000000,	RD_b|WR_T|FP_S,		0,		I1	}, /* lwc1 */
 {"l.s",     "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"lwl",     "t,~(b)",	0x60000000, 0xfc00f000,	RD_b|WR_t,		0,		I1	},
-{"lwl",     "t,o(b)",	0,    (int) M_LWL_OB,	INSN_MACRO,		0,		I1	},
 {"lwl",     "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		0,		I1	},
 {"lcache",  "t,~(b)",	0x60000000, 0xfc00f000,	RD_b|WR_t,		0,		I1	}, /* same */
-{"lcache",  "t,o(b)",	0,    (int) M_LWL_OB,	INSN_MACRO,		0,		I1	},
 {"lcache",  "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		0,		I1	},
 {"lwm",     "mN,mJ(ms)",    0x4500,     0xffc0,	NODS,			RD_sp,		I1	},
 {"lwm",     "n,~(b)",	0x20005000, 0xfc00f000,	RD_b|NODS,		0,		I1	},
-{"lwm",     "n,o(b)",	0,    (int) M_LWM_OB,	INSN_MACRO,		0,		I1	},
 {"lwm",     "n,A(b)",	0,    (int) M_LWM_AB,	INSN_MACRO,		0,		I1	},
 {"lwp",     "t,~(b)",	0x20001000, 0xfc00f000,	RD_b|WR_t|NODS,		0,		I1	},
-{"lwp",     "t,o(b)",	0,    (int) M_LWP_OB,	INSN_MACRO,		0,		I1	},
 {"lwp",     "t,A(b)",	0,    (int) M_LWP_AB,	INSN_MACRO,		0,		I1	},
 {"lwr",     "t,~(b)",	0x60001000, 0xfc00f000,	RD_b|WR_t,		0,		I1	},
-{"lwr",     "t,o(b)",	0,    (int) M_LWR_OB,	INSN_MACRO,		0,		I1	},
 {"lwr",     "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		0,		I1	},
 {"lwu",     "t,~(b)",	0x6000e000, 0xfc00f000,	RD_b|WR_t,		0,		I3	},
-{"lwu",     "t,o(b)",	0,    (int) M_LWU_OB,	INSN_MACRO,		0,		I3	},
 {"lwu",     "t,A(b)",	0,    (int) M_LWU_AB,	INSN_MACRO,		0,		I3	},
 {"lwxc1",   "D,t(b)",	0x54000048, 0xfc0007ff,	WR_D|RD_t|RD_b|FP_S,	0,		I1	},
 {"flush",   "t,~(b)",	0x60001000, 0xfc00f000,	RD_b|WR_t,		0,		I1	}, /* same */
-{"flush",   "t,o(b)",	0,    (int) M_LWR_OB,	INSN_MACRO,		0,		I1	},
 {"flush",   "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		0,		I1	},
 {"lwxs",    "d,t(b)",	0x00000118, 0xfc0007ff,	RD_b|RD_t|WR_d,		0,		I1	},
 {"madd",    "s,t",	0x0000cb3c, 0xfc00ffff,	RD_s|RD_t|MOD_HILO,	0,		I1	},
@@ -819,15 +799,12 @@ const struct mips_opcode micromips_opcod
 {"sb",      "t,o(b)",	0x18000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
 {"sb",      "t,A(b)",	0,    (int) M_SB_AB,	INSN_MACRO,		0,		I1	},
 {"sc",      "t,~(b)",	0x6000b000, 0xfc00f000,	SM|RD_t|WR_t|RD_b,	0,		I1	},
-{"sc",      "t,o(b)",	0,    (int) M_SC_OB,	INSN_MACRO,		0,		I1	},
 {"sc",      "t,A(b)",	0,    (int) M_SC_AB,	INSN_MACRO,		0,		I1	},
 {"scd",     "t,~(b)",	0x6000f000, 0xfc00f000,	SM|RD_t|WR_t|RD_b,	0,		I3	},
-{"scd",     "t,o(b)",	0,    (int) M_SCD_OB,	INSN_MACRO,		0,		I3	},
 {"scd",     "t,A(b)",	0,    (int) M_SCD_AB,	INSN_MACRO,		0,		I3	},
 /* The macro has to be first to handle o32 correctly.  */
-{"sd",      "t,o(b)",	0,    (int) M_SD_OB,	INSN_MACRO,		0,		I1	},
-{"sd",      "t,o(b)",	0xd8000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
 {"sd",      "t,A(b)",	0,    (int) M_SD_AB,	INSN_MACRO,		0,		I1	},
+{"sd",      "t,o(b)",	0xd8000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
 {"sdbbp",   "",		    0x46c0,     0xffff,	TRAP,			0,		I1	},
 {"sdbbp",   "",		0x0000db7c, 0xffffffff,	TRAP,			0,		I1	},
 {"sdbbp",   "mO",	    0x46c0,     0xfff0,	TRAP,			0,		I1	},
@@ -837,21 +814,16 @@ const struct mips_opcode micromips_opcod
 {"sdc1",    "T,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"sdc1",    "E,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"sdc2",    "E,~(b)",	0x2000a000, 0xfc00f000,	SM|RD_C2|RD_b,		0,		I1	},
-{"sdc2",    "E,o(b)",	0,    (int) M_SDC2_OB,	INSN_MACRO,		0,		I1	},
 {"sdc2",    "E,A(b)",	0,    (int) M_SDC2_AB,	INSN_MACRO,		0,		I1	},
 {"s.d",     "T,o(b)",	0xb8000000, 0xfc000000,	SM|RD_T|RD_b|FP_D,	0,		I1	}, /* sdc1 */
 {"s.d",     "T,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"sdl",     "t,~(b)",	0x6000c000, 0xfc00f000,	SM|RD_t|RD_b,		0,		I3	},
-{"sdl",     "t,o(b)",	0,    (int) M_SDL_OB,	INSN_MACRO,		0,		I3	},
 {"sdl",     "t,A(b)",	0,    (int) M_SDL_AB,	INSN_MACRO,		0,		I3	},
 {"sdm",     "n,~(b)",	0x2000f000, 0xfc00f000,	SM|RD_b,		0,		I3	},
-{"sdm",     "n,o(b)",	0,    (int) M_SDM_OB,	INSN_MACRO,		0,		I3	},
 {"sdm",     "n,A(b)",	0,    (int) M_SDM_AB,	INSN_MACRO,		0,		I3	},
 {"sdp",     "t,~(b)",	0x2000c000, 0xfc00f000,	SM|RD_t|RD_b,		0,		I3	},
-{"sdp",     "t,o(b)",	0,    (int) M_SDP_OB,	INSN_MACRO,		0,		I3	},
 {"sdp",     "t,A(b)",	0,    (int) M_SDP_AB,	INSN_MACRO,		0,		I3	},
 {"sdr",     "t,~(b)",	0x6000d000, 0xfc00f000,	SM|RD_t|RD_b,		0,		I3	},
-{"sdr",     "t,o(b)",	0,    (int) M_SDR_OB,	INSN_MACRO,		0,		I3	},
 {"sdr",     "t,A(b)",	0,    (int) M_SDR_AB,	INSN_MACRO,		0,		I3	},
 {"sdxc1",   "D,t(b)",	0x54000108, 0xfc0007ff,	SM|RD_t|RD_b|FP_D,	RD_D,		I1	},
 {"seb",     "t,r",	0x00002b3c, 0xfc00ffff,	WR_t|RD_s,		0,		I1	},
@@ -913,28 +885,21 @@ const struct mips_opcode micromips_opcod
 {"swc1",    "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"swc1",    "E,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"swc2",    "E,~(b)",	0x20008000, 0xfc00f000,	SM|RD_C2|RD_b,		0,		I1	},
-{"swc2",    "E,o(b)",	0,    (int) M_SWC2_OB,	INSN_MACRO,		0,		I1	},
 {"swc2",    "E,A(b)",	0,    (int) M_SWC2_AB,	INSN_MACRO,		0,		I1	},
 {"s.s",     "T,o(b)",	0x98000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	}, /* swc1 */
 {"s.s",     "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		INSN2_M_FP_S,	I1	},
 {"swl",     "t,~(b)",	0x60008000, 0xfc00f000,	SM|RD_t|RD_b,		0,		I1	},
-{"swl",     "t,o(b)",	0,    (int) M_SWL_OB,	INSN_MACRO,		0,		I1	},
 {"swl",     "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		0,		I1	},
 {"scache",  "t,~(b)",	0x60008000, 0xfc00f000,	SM|RD_t|RD_b,		0,		I1	}, /* same */
-{"scache",  "t,o(b)",	0,    (int) M_SWL_OB,	INSN_MACRO,		0,		I1	},
 {"scache",  "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		0,		I1	},
 {"swm",     "mN,mJ(ms)",    0x4540,     0xffc0,	NODS,			RD_sp,		I1	},
 {"swm",     "n,~(b)",	0x2000d000, 0xfc00f000,	SM|RD_b|NODS,		0,		I1	},
-{"swm",     "n,o(b)",	0,    (int) M_SWM_OB,	INSN_MACRO,		0,		I1	},
 {"swm",     "n,A(b)",	0,    (int) M_SWM_AB,	INSN_MACRO,		0,		I1	},
 {"swp",     "t,~(b)",	0x20009000, 0xfc00f000,	SM|RD_t|RD_b|NODS,	0,		I1	},
-{"swp",     "t,o(b)",	0,    (int) M_SWP_OB,	INSN_MACRO,		0,		I1	},
 {"swp",     "t,A(b)",	0,    (int) M_SWP_AB,	INSN_MACRO,		0,		I1	},
 {"swr",     "t,~(b)",	0x60009000, 0xfc00f000,	SM|RD_b|RD_t,		0,		I1	},
-{"swr",     "t,o(b)",	0,    (int) M_SWR_OB,	INSN_MACRO,		0,		I1	},
 {"swr",     "t,A(b)",	0,    (int) M_SWR_AB,	INSN_MACRO,		0,		I1	},
 {"invalidate", "t,~(b)",0x60009000, 0xfc00f000,	SM|RD_b|RD_t,		0,		I1	}, /* same */
-{"invalidate", "t,o(b)",0,    (int) M_SWR_OB,	INSN_MACRO,		0,		I1	},
 {"invalidate", "t,A(b)",0,    (int) M_SWR_AB,	INSN_MACRO,		0,		I1	},
 {"swxc1",   "D,t(b)",	0x54000088, 0xfc0007ff,	SM|RD_t|RD_b|FP_S,	RD_D,		I1	},
 {"sync_acquire", "",	0x00116b7c, 0xffffffff,	NODS,			0,		I1	},
@@ -993,20 +958,13 @@ const struct mips_opcode micromips_opcod
 {"trunc.l.s", "T,S",	0x5400233b, 0xfc00ffff,	WR_T|RD_S|FP_S|FP_D,	0,		I1	},
 {"trunc.w.d", "T,S",	0x54006b3b, 0xfc00ffff,	WR_T|RD_S|FP_S|FP_D,	0,		I1	},
 {"trunc.w.s", "T,S",	0x54002b3b, 0xfc00ffff,	WR_T|RD_S|FP_S,		0,		I1	},
-{"uld",     "t,o(b)",	0,    (int) M_ULD,	INSN_MACRO,		0,		I3	},
-{"uld",     "t,A(b)",	0,    (int) M_ULD_A,	INSN_MACRO,		0,		I3	},
-{"ulh",     "t,o(b)",	0,    (int) M_ULH,	INSN_MACRO,		0,		I1	},
-{"ulh",     "t,A(b)",	0,    (int) M_ULH_A,	INSN_MACRO,		0,		I1	},
-{"ulhu",    "t,o(b)",	0,    (int) M_ULHU,	INSN_MACRO,		0,		I1	},
-{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_A,	INSN_MACRO,		0,		I1	},
-{"ulw",     "t,o(b)",	0,    (int) M_ULW,	INSN_MACRO,		0,		I1	},
-{"ulw",     "t,A(b)",	0,    (int) M_ULW_A,	INSN_MACRO,		0,		I1	},
-{"usd",     "t,o(b)",	0,    (int) M_USD,	INSN_MACRO,		0,		I1	},
-{"usd",     "t,A(b)",	0,    (int) M_USD_A,	INSN_MACRO,		0,		I1	},
-{"ush",     "t,o(b)",	0,    (int) M_USH,	INSN_MACRO,		0,		I1	},
-{"ush",     "t,A(b)",	0,    (int) M_USH_A,	INSN_MACRO,		0,		I1	},
-{"usw",     "t,o(b)",	0,    (int) M_USW,	INSN_MACRO,		0,		I1	},
-{"usw",     "t,A(b)",	0,    (int) M_USW_A,	INSN_MACRO,		0,		I1	},
+{"uld",     "t,A(b)",	0,    (int) M_ULD_AB,	INSN_MACRO,		0,		I3	},
+{"ulh",     "t,A(b)",	0,    (int) M_ULH_AB,	INSN_MACRO,		0,		I1	},
+{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_AB,	INSN_MACRO,		0,		I1	},
+{"ulw",     "t,A(b)",	0,    (int) M_ULW_AB,	INSN_MACRO,		0,		I1	},
+{"usd",     "t,A(b)",	0,    (int) M_USD_AB,	INSN_MACRO,		0,		I1	},
+{"ush",     "t,A(b)",	0,    (int) M_USH_AB,	INSN_MACRO,		0,		I1	},
+{"usw",     "t,A(b)",	0,    (int) M_USW_AB,	INSN_MACRO,		0,		I1	},
 {"wait",    "",		0x0000937c, 0xffffffff,	NODS,			0,		I1	},
 {"wait",    "B",	0x0000937c, 0xfc00ffff,	NODS,			0,		I1	},
 {"wrpgpr",  "t,r",	0x0000f17c, 0xfc00ffff,	RD_s,			0,		I1	},
@@ -1018,52 +976,36 @@ const struct mips_opcode micromips_opcod
 {"xori",    "t,r,i",	0x70000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
 /* microMIPS Enhanced VA Scheme */
 {"lbue",   "t,+j(b)",	0x60006000, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lbue",   "t,o(b)",	0,    (int) M_LBUE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lbue",   "t,A(b)",	0,    (int) M_LBUE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhue",   "t,+j(b)",	0x60006200, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lhue",   "t,o(b)",	0,    (int) M_LHUE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhue",   "t,A(b)",	0,    (int) M_LHUE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lbe",    "t,+j(b)",	0x60006800, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lbe",    "t,o(b)",	0,    (int) M_LBE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lbe",    "t,A(b)",	0,    (int) M_LBE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhe",    "t,+j(b)",	0x60006a00, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lhe",    "t,o(b)",	0,    (int) M_LHE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhe",    "t,A(b)",	0,    (int) M_LHE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lle",    "t,+j(b)",	0x60006c00, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lle",    "t,o(b)",	0,    (int) M_LLE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lle",    "t,A(b)",	0,    (int) M_LLE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwe",    "t,+j(b)",	0x60006e00, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lwe",    "t,o(b)",	0,    (int) M_LWE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwe",    "t,A(b)",	0,    (int) M_LWE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwle",   "t,+j(b)",	0x60006400, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lwle",   "t,o(b)",	0,    (int) M_LWLE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwle",   "t,A(b)",	0,    (int) M_LWLE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwre",   "t,+j(b)",	0x60006600, 0xfc00fe00, RD_b|WR_t,	0,      0,	EVA	},
-{"lwre",   "t,o(b)",	0,    (int) M_LWRE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwre",   "t,A(b)",	0,    (int) M_LWRE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"sbe",    "t,+j(b)",	0x6000a800, 0xfc00fe00, SM|RD_b|WR_t,	0,      0,	EVA	},
-{"sbe",    "t,o(b)",	0,    (int) M_SBE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"sbe",    "t,A(b)",	0,    (int) M_SBE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"sce",    "t,+j(b)",	0x6000ac00, 0xfc00fe00, SM|RD_t|WR_t|RD_b,	0,      0,	EVA	},
-{"sce",    "t,o(b)",	0,    (int) M_SCE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"sce",    "t,A(b)",	0,    (int) M_SCE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"she",    "t,+j(b)",	0x6000aa00, 0xfc00fe00, SM|RD_b|WR_t,	0,      0,	EVA	},
-{"she",    "t,o(b)",	0,    (int) M_SHE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"she",    "t,A(b)",	0,    (int) M_SHE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"swe",    "t,+j(b)",	0x6000ae00, 0xfc00fe00, SM|RD_b|WR_t,	0,      0,	EVA	},
-{"swe",    "t,o(b)",	0,    (int) M_SWE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"swe",    "t,A(b)",	0,    (int) M_SWE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"swle",   "t,+j(b)",	0x6000a000, 0xfc00fe00, SM|RD_b|WR_t,	0,      0,	EVA	},
-{"swle",   "t,o(b)",	0,    (int) M_SWLE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"swle",   "t,A(b)",	0,    (int) M_SWLE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"swre",   "t,+j(b)",	0x6000a200, 0xfc00fe00, SM|RD_b|WR_t,	0,      0,	EVA	},
-{"swre",   "t,o(b)",	0,    (int) M_SWRE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"swre",   "t,A(b)",	0,    (int) M_SWRE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"cachee", "k,+j(b)",	0x6000a600, 0xfc00fe00, RD_b,		0,      0,	EVA	},
-{"cachee", "k,o(b)",	0,    (int) M_CACHEE_OB,INSN_MACRO,	0,      0,	EVA	},
 {"cachee", "k,A(b)",	0,    (int) M_CACHEE_AB,INSN_MACRO,	0,      0,	EVA	},
 {"prefe",  "k,+j(b)",	0x6000a400, 0xfc00fe00, RD_b,		0,      0,	EVA	},
-{"prefe",  "k,o(b)",	0,    (int) M_PREFE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"prefe",  "k,A(b)",	0,    (int) M_PREFE_AB,	INSN_MACRO,	0,      0,	EVA	},
 /* MIPS DSP ASE.  */
 {"absq_s.ph", "t,s",	0x0000113c, 0xfc00ffff,	WR_t|RD_s,		0,		0,	D32	},
Index: opcodes/mips-opc.c
===================================================================
--- opcodes/mips-opc.c	2013-07-07 11:52:40.403442316 +0100
+++ opcodes/mips-opc.c	2013-07-07 11:52:43.109465791 +0100
@@ -300,7 +300,6 @@ const struct mips_opcode mips_builtin_op
 {"abs.ps",  "D,V",	0x46c00005, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5_33|IL2F	},
 {"abs.ps",  "D,V",	0x45600005, 0xffff003f,	WR_D|RD_S|FP_D,		0,		IL2E	},
 {"aclr",    "\\,~(b)",	0x04070000, 0xfc1f8000,	SM|RD_b|NODS,		0,		0,	MC	},
-{"aclr",    "\\,o(b)",	0,    (int) M_ACLR_OB,	INSN_MACRO,		0,		0,	MC	},
 {"aclr",    "\\,A(b)",	0,    (int) M_ACLR_AB,	INSN_MACRO,		0,		0,	MC	},
 {"add",     "d,v,t",	0x00000020, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
 {"add",     "t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		0,		I1	},
@@ -340,7 +339,6 @@ const struct mips_opcode mips_builtin_op
 {"and.qh",  "X,Y,Q",	0x7820000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		0,	MX	},
 {"andi",    "t,r,i",	0x30000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
 {"aset",    "\\,~(b)",	0x04078000, 0xfc1f8000,	SM|RD_b|NODS,		0,		0,	MC	},
-{"aset",    "\\,o(b)",	0,    (int) M_ASET_OB,	INSN_MACRO,		0,		0,	MC	},
 {"aset",    "\\,A(b)",	0,    (int) M_ASET_AB,	INSN_MACRO,		0,		0,	MC	},
 {"baddu",   "d,v,t",	0x70000028, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		IOCT	},
 /* b is at the top of the table.  */
@@ -869,9 +867,8 @@ const struct mips_opcode mips_builtin_op
 {"lwux",    "d,t(b)",	0x7c00040a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		IOCT2	},
 {"lca",     "t,A(b)",	0,    (int) M_LCA_AB,	INSN_MACRO,		0,		I1	},
 /* The macro has to be first to handle o32 correctly.  */
-{"ld",      "t,o(b)",	0,    (int) M_LD_OB,	INSN_MACRO,		0,		I1	},
-{"ld",      "t,o(b)",	0xdc000000, 0xfc000000, WR_t|RD_b,		0,		I3	},
 {"ld",      "t,A(b)",	0,    (int) M_LD_AB,	INSN_MACRO,		0,		I1	},
+{"ld",      "t,o(b)",	0xdc000000, 0xfc000000, WR_t|RD_b,		0,		I3	},
 {"ldaddw",  "t,b",	0x70000010, 0xfc00ffff,	SM|RD_t|WR_t|RD_b,	0,		XLR	},
 {"ldaddwu", "t,b",	0x70000011, 0xfc00ffff,	SM|RD_t|WR_t|RD_b,	0,		XLR	},
 {"ldaddd",  "t,b",	0x70000012, 0xfc00ffff,	SM|RD_t|WR_t|RD_b,	0,		XLR	},
@@ -880,7 +877,6 @@ const struct mips_opcode mips_builtin_op
 {"ldc1",    "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I2,	0,	SF	},
 {"ldc1",    "E,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		INSN2_M_FP_D,	I2,	0,	SF	},
 {"l.d",     "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2,	0,	SF	}, /* ldc1 */
-{"l.d",     "T,o(b)",	0,    (int) M_L_DOB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"l.d",     "T,A(b)",	0,    (int) M_L_DAB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"ldc2",    "E,o(b)",	0xd8000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I2,	0,	IOCT|IOCTP|IOCT2|EE	},
 {"ldc2",    "E,A(b)",	0,    (int) M_LDC2_AB,	INSN_MACRO,		0,		I2,	0,	IOCT|IOCTP|IOCT2|EE	},
@@ -1397,10 +1393,8 @@ const struct mips_opcode mips_builtin_op
 {"rzu.ob",  "X,Q",	0x78000020, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	SB1,	MX	},
 {"rzu.ob",  "D,Q",	0x48000020, 0xfc20f83f,	WR_D|RD_S|RD_T,		0,		N54	},
 {"rzu.qh",  "X,Q",	0x78200020, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	0,	MX	},
-{"saa",	    "t,o(b)",	0,    (int) M_SAA_OB,	INSN_MACRO,		0,		IOCTP	},
 {"saa",	    "t,A(b)",	0,    (int) M_SAA_AB,	INSN_MACRO,		0,		IOCTP	},
 {"saa",	    "t,(b)",	0x70000018, 0xfc00ffff, SM|RD_t|RD_b,		0,		IOCTP	},
-{"saad",    "t,o(b)",	0,    (int) M_SAAD_OB,	INSN_MACRO,		0,		IOCTP	},
 {"saad",    "t,A(b)",	0,    (int) M_SAAD_AB,	INSN_MACRO,		0,		IOCTP	},
 {"saad",    "t,(b)",	0x70000019, 0xfc00ffff,	SM|RD_t|RD_b,		0,		IOCTP	},
 {"sb",      "t,o(b)",	0xa0000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
@@ -1410,9 +1404,8 @@ const struct mips_opcode mips_builtin_op
 {"scd",	    "t,o(b)",	0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	0,		I3,	0,	EE	},
 {"scd",	    "t,A(b)",	0,    (int) M_SCD_AB,	INSN_MACRO,		0,		I3,	0,	EE	},
 /* The macro has to be first to handle o32 correctly.  */
-{"sd",      "t,o(b)",	0,    (int) M_SD_OB,	INSN_MACRO,		0,		I1	},
-{"sd",      "t,o(b)",	0xfc000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
 {"sd",      "t,A(b)",	0,    (int) M_SD_AB,	INSN_MACRO,		0,		I1	},
+{"sd",      "t,o(b)",	0xfc000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
 {"sdbbp",   "",		0x0000000e, 0xffffffff,	TRAP,           	0,		G2	},
 {"sdbbp",   "c",	0x0000000e, 0xfc00ffff,	TRAP,			0,		G2	},
 {"sdbbp",   "c,q",	0x0000000e, 0xfc00003f,	TRAP,			0,		G2	},
@@ -1427,7 +1420,6 @@ const struct mips_opcode mips_builtin_op
 {"sdc3",    "E,o(b)",	0xfc000000, 0xfc000000,	SM|RD_C3|RD_b,		0,		I2,	0,	IOCT|IOCTP|IOCT2|EE	},
 {"sdc3",    "E,A(b)",	0,    (int) M_SDC3_AB,	INSN_MACRO,		0,		I2,	0,	IOCT|IOCTP|IOCT2|EE	},
 {"s.d",     "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2,	0,	SF	},
-{"s.d",     "T,o(b)",	0,    (int) M_S_DOB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"s.d",     "T,A(b)",	0,    (int) M_S_DAB,	INSN_MACRO,		INSN2_M_FP_D,	I1	},
 {"sdl",     "t,o(b)",	0xb0000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
 {"sdl",     "t,A(b)",	0,    (int) M_SDL_AB,	INSN_MACRO,		0,		I3	},
@@ -1636,20 +1628,13 @@ const struct mips_opcode mips_builtin_op
 {"trunc.w.s", "D,S",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I2,	0,	EE	},
 {"trunc.w.s", "D,S,x",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I2,	0,	EE	},
 {"trunc.w.s", "D,S,t",	0,    (int) M_TRUNCWS,	INSN_MACRO,		INSN2_M_FP_S,	I1,	0,	EE	},
-{"uld",     "t,o(b)",	0,    (int) M_ULD,	INSN_MACRO,		0,		I3	},
-{"uld",     "t,A(b)",	0,    (int) M_ULD_A,	INSN_MACRO,		0,		I3	},
-{"ulh",     "t,o(b)",	0,    (int) M_ULH,	INSN_MACRO,		0,		I1	},
-{"ulh",     "t,A(b)",	0,    (int) M_ULH_A,	INSN_MACRO,		0,		I1	},
-{"ulhu",    "t,o(b)",	0,    (int) M_ULHU,	INSN_MACRO,		0,		I1	},
-{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_A,	INSN_MACRO,		0,		I1	},
-{"ulw",     "t,o(b)",	0,    (int) M_ULW,	INSN_MACRO,		0,		I1	},
-{"ulw",     "t,A(b)",	0,    (int) M_ULW_A,	INSN_MACRO,		0,		I1	},
-{"usd",     "t,o(b)",	0,    (int) M_USD,	INSN_MACRO,		0,		I3	},
-{"usd",     "t,A(b)",	0,    (int) M_USD_A,	INSN_MACRO,		0,		I3	},
-{"ush",     "t,o(b)",	0,    (int) M_USH,	INSN_MACRO,		0,		I1	},
-{"ush",     "t,A(b)",	0,    (int) M_USH_A,	INSN_MACRO,		0,		I1	},
-{"usw",     "t,o(b)",	0,    (int) M_USW,	INSN_MACRO,		0,		I1	},
-{"usw",     "t,A(b)",	0,    (int) M_USW_A,	INSN_MACRO,		0,		I1	},
+{"uld",     "t,A(b)",	0,    (int) M_ULD_AB,	INSN_MACRO,		0,		I3	},
+{"ulh",     "t,A(b)",	0,    (int) M_ULH_AB,	INSN_MACRO,		0,		I1	},
+{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_AB,	INSN_MACRO,		0,		I1	},
+{"ulw",     "t,A(b)",	0,    (int) M_ULW_AB,	INSN_MACRO,		0,		I1	},
+{"usd",     "t,A(b)",	0,    (int) M_USD_AB,	INSN_MACRO,		0,		I3	},
+{"ush",     "t,A(b)",	0,    (int) M_USH_AB,	INSN_MACRO,		0,		I1	},
+{"usw",     "t,A(b)",	0,    (int) M_USW_AB,	INSN_MACRO,		0,		I1	},
 {"v3mulu",  "d,v,t",	0x70000011, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		IOCT	},
 {"vmm0",    "d,v,t",	0x70000010, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		IOCT	},
 {"vmulu",   "d,v,t",	0x7000000f, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		IOCT	},
@@ -2258,52 +2243,36 @@ const struct mips_opcode mips_builtin_op
 {"sequ",	"S,T",		0x4b80000c,	0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,	IL2F|IL3A	},
 /* MIPS Enhanced VA Scheme */
 {"lbue",   "t,+j(b)",	0x7c000028, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lbue",   "t,o(b)",	0,    (int) M_LBUE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lbue",   "t,A(b)",	0,    (int) M_LBUE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhue",   "t,+j(b)",	0x7c000029, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lhue",   "t,o(b)",	0,    (int) M_LHUE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhue",   "t,A(b)",	0,    (int) M_LHUE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lbe",    "t,+j(b)",	0x7c00002c, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lbe",    "t,o(b)",	0,    (int) M_LBE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lbe",    "t,A(b)",	0,    (int) M_LBE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhe",    "t,+j(b)",	0x7c00002d, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lhe",    "t,o(b)",	0,    (int) M_LHE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lhe",    "t,A(b)",	0,    (int) M_LHE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lle",    "t,+j(b)",	0x7c00002e, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lle",    "t,o(b)",	0,    (int) M_LLE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lle",    "t,A(b)",	0,    (int) M_LLE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwe",    "t,+j(b)",	0x7c00002f, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lwe",    "t,o(b)",	0,    (int) M_LWE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwe",    "t,A(b)",	0,    (int) M_LWE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwle",   "t,+j(b)",	0x7c000019, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lwle",   "t,o(b)",	0,    (int) M_LWLE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwle",   "t,A(b)",	0,    (int) M_LWLE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwre",   "t,+j(b)",	0x7c00001a, 0xfc00007f, LDD|RD_b|WR_t,	0,      0,	EVA	},
-{"lwre",   "t,o(b)",	0,    (int) M_LWRE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"lwre",   "t,A(b)",	0,    (int) M_LWRE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"sbe",    "t,+j(b)",	0x7c00001c, 0xfc00007f, SM|RD_t|RD_b,	0,      0,	EVA	},
-{"sbe",    "t,o(b)",	0,    (int) M_SBE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"sbe",    "t,A(b)",	0,    (int) M_SBE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"sce",    "t,+j(b)",	0x7c00001e, 0xfc00007f, SM|RD_t|WR_t|RD_b,	0,      0,	EVA	},
-{"sce",    "t,o(b)",	0,    (int) M_SCE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"sce",    "t,A(b)",	0,    (int) M_SCE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"she",    "t,+j(b)",	0x7c00001d, 0xfc00007f, SM|RD_t|RD_b,	0,      0,	EVA	},
-{"she",    "t,o(b)",	0,    (int) M_SHE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"she",    "t,A(b)",	0,    (int) M_SHE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"swe",    "t,+j(b)",	0x7c00001f, 0xfc00007f, SM|RD_t|RD_b,	0,      0,	EVA	},
-{"swe",    "t,o(b)",	0,    (int) M_SWE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"swe",    "t,A(b)",	0,    (int) M_SWE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"swle",   "t,+j(b)",	0x7c000021, 0xfc00007f, SM|RD_t|RD_b,	0,      0,	EVA	},
-{"swle",   "t,o(b)",	0,    (int) M_SWLE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"swle",   "t,A(b)",	0,    (int) M_SWLE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"swre",   "t,+j(b)",	0x7c000022, 0xfc00007f, SM|RD_t|RD_b,	0,      0,	EVA	},
-{"swre",   "t,o(b)",	0,    (int) M_SWRE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"swre",   "t,A(b)",	0,    (int) M_SWRE_AB,	INSN_MACRO,	0,      0,	EVA	},
 {"cachee", "k,+j(b)",	0x7c00001b, 0xfc00007f, RD_b,		0,      0,	EVA	},
-{"cachee", "k,o(b)",	0,    (int) M_CACHEE_OB,INSN_MACRO,	0,      0,	EVA	},
 {"cachee", "k,A(b)",	0,    (int) M_CACHEE_AB,INSN_MACRO,	0,      0,	EVA	},
 {"prefe",  "k,+j(b)",	0x7c000023, 0xfc00007f, RD_b,		0,      0,	EVA	},
-{"prefe",  "k,o(b)",	0,    (int) M_PREFE_OB,	INSN_MACRO,	0,      0,	EVA	},
 {"prefe",  "k,A(b)",	0,    (int) M_PREFE_AB,	INSN_MACRO,	0,      0,	EVA	},
 /* No hazard protection on coprocessor instructions--they shouldn't
    change the state of the processor and if they do it's up to the
Index: gas/config/tc-mips.c
===================================================================
--- gas/config/tc-mips.c	2013-07-07 11:52:40.403442316 +0100
+++ gas/config/tc-mips.c	2013-07-07 11:52:43.105465756 +0100
@@ -3096,6 +3096,13 @@ jalr_reloc_p (bfd_reloc_code_real_type r
   return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
 }
 
+static inline bfd_boolean
+gprel16_reloc_p (bfd_reloc_code_real_type reloc)
+{
+  return (reloc == BFD_RELOC_GPREL16 || reloc == BFD_RELOC_MIPS16_GPREL
+	  || reloc == BFD_RELOC_MICROMIPS_GPREL16);
+}
+
 /* Return true if RELOC is a PC-relative relocation that does not have
    full address range.  */
 
@@ -5265,8 +5272,15 @@ macro_read_relocs (va_list *args, bfd_re
   if (next >= 0)
     r[0] = (bfd_reloc_code_real_type) next;
   else
-    for (i = 0; i < 3; i++)
-      r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
+    {
+      for (i = 0; i < 3; i++)
+	r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
+      /* This function is only used for 16-bit relocation fields.
+	 To make the macro code simpler, treat an unrelocated value
+	 in the same way as BFD_RELOC_LO16.  */
+      if (r[0] == BFD_RELOC_UNUSED)
+	r[0] = BFD_RELOC_LO16;
+    }
 }
 
 /* Build an instruction created by a macro expansion.  This is passed
@@ -6734,6 +6748,48 @@ macro_build_branch_rsrt (int type, expre
     macro_build (ep, br, "s,t,p", sreg, treg);
 }
 
+/* Return the high part that should be loaded in order to make the low
+   part of VALUE accessible using an offset of OFFBITS bits.  */
+
+static offsetT
+offset_high_part (offsetT value, unsigned int offbits)
+{
+  offsetT bias;
+  addressT low_mask;
+
+  if (offbits == 0)
+    return value;
+  bias = 1 << (offbits - 1);
+  low_mask = bias * 2 - 1;
+  return (value + bias) & ~low_mask;
+}
+
+/* Return true if the value stored in offset_expr and offset_reloc
+   fits into a signed offset of OFFBITS bits.  RANGE is the maximum
+   amount that the caller wants to add without inducing overflow
+   and ALIGN is the known alignment of the value in bytes.  */
+
+static bfd_boolean
+small_offset_p (unsigned int range, unsigned int align, unsigned int offbits)
+{
+  if (offbits == 16)
+    {
+      /* Accept any relocation operator if overflow isn't a concern.  */
+      if (range < align && *offset_reloc != BFD_RELOC_UNUSED)
+	return TRUE;
+
+      /* These relocations are guaranteed not to overflow in correct links.  */
+      if (*offset_reloc == BFD_RELOC_MIPS_LITERAL
+	  || gprel16_reloc_p (*offset_reloc))
+	return TRUE;
+    }
+  if (offset_expr.X_op == O_constant
+      && offset_high_part (offset_expr.X_add_number, offbits) == 0
+      && offset_high_part (offset_expr.X_add_number + range, offbits) == 0)
+    return TRUE;
+  return FALSE;
+}
+
 /*
  *			Build macros
  *   This routine implements the seemingly endless macro or synthesized
@@ -6774,10 +6830,10 @@ macro (struct mips_cl_insn *ip, char *st
   int imm = 0;
   int ust = 0;
   int lp = 0;
-  int ab = 0;
+  bfd_boolean large_offset;
   int off;
-  bfd_reloc_code_real_type r;
   int hold_mips_optimize;
+  unsigned int align;
 
   gas_assert (! mips_opts.mips16);
 
@@ -6795,6 +6851,7 @@ macro (struct mips_cl_insn *ip, char *st
   expr1.X_op_symbol = NULL;
   expr1.X_add_symbol = NULL;
   expr1.X_add_number = 1;
+  align = 1;
 
   switch (mask)
     {
@@ -7540,12 +7597,10 @@ macro (struct mips_cl_insn *ip, char *st
       if (!dbl && HAVE_64BIT_OBJECTS)
 	as_warn (_("la used to load 64-bit address"));
 
-      if (offset_expr.X_op == O_constant
-	  && offset_expr.X_add_number >= -0x8000
-	  && offset_expr.X_add_number < 0x8000)
+      if (small_offset_p (0, align, 16))
 	{
-	  macro_build (&offset_expr, ADDRESS_ADDI_INSN,
-		       "t,r,j", treg, sreg, BFD_RELOC_LO16);
+	  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, breg,
+		       -1, offset_reloc[0], offset_reloc[1], offset_reloc[2]);
 	  break;
 	}
 
@@ -8397,146 +8452,108 @@ macro (struct mips_cl_insn *ip, char *st
       break;
 
     case M_LBUE_AB:
-      ab = 1;
-    case M_LBUE_OB:
       s = "lbue";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LHUE_AB:
-      ab = 1;
-    case M_LHUE_OB:
       s = "lhue";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LBE_AB:
-      ab = 1;
-    case M_LBE_OB:
       s = "lbe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LHE_AB:
-      ab = 1;
-    case M_LHE_OB:
       s = "lhe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LLE_AB:
-      ab = 1;
-    case M_LLE_OB:
       s = "lle";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LWE_AB:
-      ab = 1;
-    case M_LWE_OB:
       s = "lwe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LWLE_AB:
-      ab = 1;
-    case M_LWLE_OB:
       s = "lwle";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_LWRE_AB:
-      ab = 1;
-    case M_LWRE_OB:
       s = "lwre";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SBE_AB:
-      ab = 1;
-    case M_SBE_OB:
       s = "sbe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SCE_AB:
-      ab = 1;
-    case M_SCE_OB:
       s = "sce";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SHE_AB:
-      ab = 1;
-    case M_SHE_OB:
       s = "she";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SWE_AB:
-      ab = 1;
-    case M_SWE_OB:
       s = "swe";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SWLE_AB:
-      ab = 1;
-    case M_SWLE_OB:
       s = "swle";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SWRE_AB:
-      ab = 1;
-    case M_SWRE_OB:
       s = "swre";
       fmt = "t,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_ACLR_AB:
-      ab = 1;
-    case M_ACLR_OB:
       s = "aclr";
       treg = EXTRACT_OPERAND (mips_opts.micromips, 3BITPOS, *ip);
       fmt = "\\,~(b)";
       offbits = 12;
       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)";
       offbits = 12;
       goto ld_st;
     case M_LB_AB:
-      ab = 1;
       s = "lb";
       fmt = "t,o(b)";
       goto ld;
     case M_LBU_AB:
-      ab = 1;
       s = "lbu";
       fmt = "t,o(b)";
       goto ld;
     case M_LH_AB:
-      ab = 1;
       s = "lh";
       fmt = "t,o(b)";
       goto ld;
     case M_LHU_AB:
-      ab = 1;
       s = "lhu";
       fmt = "t,o(b)";
       goto ld;
     case M_LW_AB:
-      ab = 1;
       s = "lw";
       fmt = "t,o(b)";
       goto ld;
     case M_LWC0_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "lwc0";
       fmt = "E,o(b)";
@@ -8544,15 +8561,12 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_LWC1_AB:
-      ab = 1;
       s = "lwc1";
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LWC2_AB:
-      ab = 1;
-    case M_LWC2_OB:
       s = "lwc2";
       fmt = COP12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8560,7 +8574,6 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_LWC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "lwc3";
       fmt = "E,o(b)";
@@ -8568,29 +8581,22 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_LWL_AB:
-      ab = 1;
-    case M_LWL_OB:
       s = "lwl";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LWR_AB:
-      ab = 1;
-    case M_LWR_OB:
       s = "lwr";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LDC1_AB:
-      ab = 1;
       s = "ldc1";
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LDC2_AB:
-      ab = 1;
-    case M_LDC2_OB:
       s = "ldc2";
       fmt = COP12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8598,57 +8604,43 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_LQC2_AB:
-      ab = 1;
       s = "lqc2";
       fmt = "E,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LDC3_AB:
-      ab = 1;
       s = "ldc3";
       fmt = "E,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_LDL_AB:
-      ab = 1;
-    case M_LDL_OB:
       s = "ldl";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LDR_AB:
-      ab = 1;
-    case M_LDR_OB:
       s = "ldr";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_LL_AB:
-      ab = 1;
-    case M_LL_OB:
       s = "ll";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LLD_AB:
-      ab = 1;
-    case M_LLD_OB:
       s = "lld";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LWU_AB:
-      ab = 1;
-    case M_LWU_OB:
       s = "lwu";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld;
     case M_LWP_AB:
-      ab = 1;
-    case M_LWP_OB:
       gas_assert (mips_opts.micromips);
       s = "lwp";
       fmt = "t,~(b)";
@@ -8656,8 +8648,6 @@ macro (struct mips_cl_insn *ip, char *st
       lp = 1;
       goto ld;
     case M_LDP_AB:
-      ab = 1;
-    case M_LDP_OB:
       gas_assert (mips_opts.micromips);
       s = "ldp";
       fmt = "t,~(b)";
@@ -8665,16 +8655,12 @@ macro (struct mips_cl_insn *ip, char *st
       lp = 1;
       goto ld;
     case M_LWM_AB:
-      ab = 1;
-    case M_LWM_OB:
       gas_assert (mips_opts.micromips);
       s = "lwm";
       fmt = "n,~(b)";
       offbits = 12;
       goto ld_st;
     case M_LDM_AB:
-      ab = 1;
-    case M_LDM_OB:
       gas_assert (mips_opts.micromips);
       s = "ldm";
       fmt = "n,~(b)";
@@ -8690,22 +8676,18 @@ macro (struct mips_cl_insn *ip, char *st
       goto ld_noat;
 
     case M_SB_AB:
-      ab = 1;
       s = "sb";
       fmt = "t,o(b)";
       goto ld_st;
     case M_SH_AB:
-      ab = 1;
       s = "sh";
       fmt = "t,o(b)";
       goto ld_st;
     case M_SW_AB:
-      ab = 1;
       s = "sw";
       fmt = "t,o(b)";
       goto ld_st;
     case M_SWC0_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "swc0";
       fmt = "E,o(b)";
@@ -8713,15 +8695,12 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_SWC1_AB:
-      ab = 1;
       s = "swc1";
       fmt = "T,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_SWC2_AB:
-      ab = 1;
-    case M_SWC2_OB:
       s = "swc2";
       fmt = COP12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8729,7 +8708,6 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_SWC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "swc3";
       fmt = "E,o(b)";
@@ -8737,71 +8715,52 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_SWL_AB:
-      ab = 1;
-    case M_SWL_OB:
       s = "swl";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SWR_AB:
-      ab = 1;
-    case M_SWR_OB:
       s = "swr";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SC_AB:
-      ab = 1;
-    case M_SC_OB:
       s = "sc";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SCD_AB:
-      ab = 1;
-    case M_SCD_OB:
       s = "scd";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_CACHE_AB:
-      ab = 1;
-    case M_CACHE_OB:
       s = "cache";
       fmt = mips_opts.micromips ? "k,~(b)" : "k,o(b)";
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_CACHEE_AB:
-      ab = 1;
-    case M_CACHEE_OB:
       s = "cachee";
       fmt = "k,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_PREF_AB:
-      ab = 1;
-    case M_PREF_OB:
       s = "pref";
       fmt = !mips_opts.micromips ? "k,o(b)" : "k,~(b)";
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_PREFE_AB:
-      ab = 1;
-    case M_PREFE_OB:
       s = "prefe";
       fmt = "k,+j(b)";
       offbits = 9;
       goto ld_st;
     case M_SDC1_AB:
-      ab = 1;
       s = "sdc1";
       fmt = "T,o(b)";
       coproc = 1;
       /* Itbl support may require additional care here.  */
       goto ld_st;
     case M_SDC2_AB:
-      ab = 1;
-    case M_SDC2_OB:
       s = "sdc2";
       fmt = COP12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -8809,14 +8768,12 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_SQC2_AB:
-      ab = 1;
       s = "sqc2";
       fmt = "E,o(b)";
       /* Itbl support may require additional care here.  */
       coproc = 1;
       goto ld_st;
     case M_SDC3_AB:
-      ab = 1;
       gas_assert (!mips_opts.micromips);
       s = "sdc3";
       fmt = "E,o(b)";
@@ -8824,46 +8781,34 @@ macro (struct mips_cl_insn *ip, char *st
       coproc = 1;
       goto ld_st;
     case M_SDL_AB:
-      ab = 1;
-    case M_SDL_OB:
       s = "sdl";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SDR_AB:
-      ab = 1;
-    case M_SDR_OB:
       s = "sdr";
       fmt = MEM12_FMT;
       offbits = (mips_opts.micromips ? 12 : 16);
       goto ld_st;
     case M_SWP_AB:
-      ab = 1;
-    case M_SWP_OB:
       gas_assert (mips_opts.micromips);
       s = "swp";
       fmt = "t,~(b)";
       offbits = 12;
       goto ld_st;
     case M_SDP_AB:
-      ab = 1;
-    case M_SDP_OB:
       gas_assert (mips_opts.micromips);
       s = "sdp";
       fmt = "t,~(b)";
       offbits = 12;
       goto ld_st;
     case M_SWM_AB:
-      ab = 1;
-    case M_SWM_OB:
       gas_assert (mips_opts.micromips);
       s = "swm";
       fmt = "n,~(b)";
       offbits = 12;
       goto ld_st;
     case M_SDM_AB:
-      ab = 1;
-    case M_SDM_OB:
       gas_assert (mips_opts.micromips);
       s = "sdm";
       fmt = "n,~(b)";
@@ -8871,8 +8816,41 @@ macro (struct mips_cl_insn *ip, char *st
 
     ld_st:
       tempreg = AT;
-      used_at = 1;
     ld_noat:
+      if (small_offset_p (0, align, 16))
+	{
+	  /* The first case exists for M_LD_AB and M_SD_AB, which are
+	     macros for o32 but which should act like normal instructions
+	     otherwise.  */
+	  if (offbits == 16)
+	    macro_build (&offset_expr, s, fmt, treg, -1, offset_reloc[0],
+			 offset_reloc[1], offset_reloc[2], breg);
+	  else if (small_offset_p (0, align, offbits))
+	    {
+	      if (offbits == 0)
+		macro_build (NULL, s, fmt, treg, breg);
+	      else
+		macro_build (NULL, s, fmt, treg,
+			     (unsigned long) offset_expr.X_add_number, breg);
+	    }
+	  else
+	    {
+	      if (tempreg == AT)
+		used_at = 1;
+	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+			   tempreg, breg, -1, offset_reloc[0],
+			   offset_reloc[1], offset_reloc[2]);
+	      if (offbits == 0)
+		macro_build (NULL, s, fmt, treg, tempreg);
+	      else
+		macro_build (NULL, s, fmt, treg, 0L, tempreg);
+	    }
+	  break;
+	}
+
+      if (tempreg == AT)
+	used_at = 1;
+
       if (offset_expr.X_op != O_constant
 	  && offset_expr.X_op != O_symbol)
 	{
@@ -8893,79 +8871,40 @@ macro (struct mips_cl_insn *ip, char *st
 	 is in non PIC code.  */
       if (offset_expr.X_op == O_constant)
 	{
-	  int hipart = 0;
+	  expr1.X_add_number = offset_high_part (offset_expr.X_add_number,
+						 offbits == 0 ? 16 : offbits);
+	  offset_expr.X_add_number -= expr1.X_add_number;
 
-	  expr1.X_add_number = offset_expr.X_add_number;
-	  normalize_address_expr (&expr1);
-	  if ((offbits == 0 || offbits == 16)
-	      && !IS_SEXT_16BIT_NUM (expr1.X_add_number))
-	    {
-	      expr1.X_add_number = ((expr1.X_add_number + 0x8000)
-				    & ~(bfd_vma) 0xffff);
-	      hipart = 1;
-	    }
-	  else if (offbits == 12 && !IS_SEXT_12BIT_NUM (expr1.X_add_number))
-	    {
-	      expr1.X_add_number = ((expr1.X_add_number + 0x800)
-				    & ~(bfd_vma) 0xfff);
-	      hipart = 1;
-	    }
-	  else if (offbits == 9 && !IS_SEXT_9BIT_NUM (expr1.X_add_number))
-	    {
-	      expr1.X_add_number = ((expr1.X_add_number + 0x100)
-				    & ~(bfd_vma) 0x1ff);
-	      hipart = 1;
-	    }
-	  if (hipart)
-	    {
-	      load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
-	      if (breg != 0)
-		macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
-			     tempreg, tempreg, breg);
-	      breg = tempreg;
-	    }
+	  load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
+	  if (breg != 0)
+	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+			 tempreg, tempreg, breg);
 	  if (offbits == 0)
 	    {
-	      if (offset_expr.X_add_number == 0)
-		tempreg = breg;
-	      else
+	      if (offset_expr.X_add_number != 0)
 		macro_build (&offset_expr, ADDRESS_ADDI_INSN,
-			     "t,r,j", tempreg, breg, BFD_RELOC_LO16);
+			     "t,r,j", tempreg, tempreg, BFD_RELOC_LO16);
 	      macro_build (NULL, s, fmt, treg, tempreg);
 	    }
 	  else if (offbits == 16)
-	    macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, breg);
+	    macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
 	  else
-	    macro_build (NULL, s, fmt,
-			 treg, (unsigned long) offset_expr.X_add_number, breg);
+	    macro_build (NULL, s, fmt, treg,
+			 (unsigned long) offset_expr.X_add_number, tempreg);
 	}
       else if (offbits != 16)
 	{
 	  /* The 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;
+	     register.  */
+	  load_address (tempreg, &offset_expr, &used_at);
+	  if (breg != 0)
+	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+			 tempreg, tempreg, breg);
 	  if (offbits == 0)
 	    macro_build (NULL, s, fmt, treg, tempreg);
 	  else
-	    macro_build (NULL, s, fmt,
-		         treg, (unsigned long) expr1.X_add_number, tempreg);
+	    macro_build (NULL, s, fmt, treg, 0L, tempreg);
 	}
       else if (mips_pic == NO_PIC)
 	{
@@ -9423,16 +9362,11 @@ macro (struct mips_cl_insn *ip, char *st
 		  && offset_expr.X_add_number == 0);
       s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
       if (strcmp (s, ".lit8") == 0)
-	{
-	  if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips)
-	    {
-	      macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
-			   BFD_RELOC_MIPS_LITERAL, mips_gp_register);
-	      break;
-	    }
-	  breg = mips_gp_register;
-	  r = BFD_RELOC_MIPS_LITERAL;
-	  goto dob;
+ 	{
+ 	  breg = mips_gp_register;
+	  offset_reloc[0] = BFD_RELOC_MIPS_LITERAL;
+	  offset_reloc[1] = BFD_RELOC_UNUSED;
+	  offset_reloc[2] = BFD_RELOC_UNUSED;
 	}
       else
 	{
@@ -9447,47 +9381,15 @@ macro (struct mips_cl_insn *ip, char *st
 	      macro_build_lui (&offset_expr, AT);
 	    }
 
-	  if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips)
-	    {
-	      macro_build (&offset_expr, "ldc1", "T,o(b)",
-			   treg, BFD_RELOC_LO16, AT);
-	      break;
-	    }
 	  breg = AT;
-	  r = BFD_RELOC_LO16;
-	  goto dob;
-	}
-
-    case M_L_DOB:
-      /* Even on a big endian machine $fn comes before $fn+1.  We have
-	 to adjust when loading from memory.  */
-      r = BFD_RELOC_LO16;
-    dob:
-      gas_assert (!mips_opts.micromips);
-      gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
-      macro_build (&offset_expr, "lwc1", "T,o(b)",
-		   target_big_endian ? treg + 1 : treg, r, breg);
-      /* FIXME: A possible overflow which I don't know how to deal
-	 with.  */
-      offset_expr.X_add_number += 4;
-      macro_build (&offset_expr, "lwc1", "T,o(b)",
-		   target_big_endian ? treg : treg + 1, r, breg);
-      break;
-
-    case M_S_DOB:
-      gas_assert (!mips_opts.micromips);
-      gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch));
-      /* Even on a big endian machine $fn comes before $fn+1.  We have
-	 to adjust when storing to memory.  */
-      macro_build (&offset_expr, "swc1", "T,o(b)",
-		   target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
-      offset_expr.X_add_number += 4;
-      macro_build (&offset_expr, "swc1", "T,o(b)",
-		   target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
-      break;
+	  offset_reloc[0] = BFD_RELOC_LO16;
+	  offset_reloc[1] = BFD_RELOC_UNUSED;
+	  offset_reloc[2] = BFD_RELOC_UNUSED;
+ 	}
+      align = 8;
+      /* Fall through */
 
     case M_L_DAB:
-      gas_assert (!mips_opts.micromips);
       /*
        * The MIPS assembler seems to check for X_add_number not
        * being double aligned and generating:
@@ -9553,6 +9455,51 @@ macro (struct mips_cl_insn *ip, char *st
       s = "sw";
 
     ldd_std:
+      /* Even on a big endian machine $fn comes before $fn+1.  We have
+	 to adjust when loading from memory.  We set coproc if we must
+	 load $fn+1 first.  */
+      /* Itbl support may require additional care here.  */
+      if (!target_big_endian)
+	coproc = 0;
+
+      if (small_offset_p (0, align, 16))
+	{
+	  ep = &offset_expr;
+	  if (!small_offset_p (4, align, 16))
+	    {
+	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", AT, breg,
+			   -1, offset_reloc[0], offset_reloc[1],
+			   offset_reloc[2]);
+	      expr1.X_add_number = 0;
+	      ep = &expr1;
+	      breg = AT;
+	      used_at = 1;
+	      offset_reloc[0] = BFD_RELOC_LO16;
+	      offset_reloc[1] = BFD_RELOC_UNUSED;
+	      offset_reloc[2] = BFD_RELOC_UNUSED;
+	    }
+	  if (strcmp (s, "lw") == 0 && treg == breg)
+	    {
+	      ep->X_add_number += 4;
+	      macro_build (ep, s, fmt, treg + 1, -1, offset_reloc[0],
+			   offset_reloc[1], offset_reloc[2], breg);
+	      ep->X_add_number -= 4;
+	      macro_build (ep, s, fmt, treg, -1, offset_reloc[0],
+			   offset_reloc[1], offset_reloc[2], breg);
+	    }
+	  else
+	    {
+	      macro_build (ep, s, fmt, coproc ? treg + 1 : treg, -1,
+			   offset_reloc[0], offset_reloc[1], offset_reloc[2],
+			   breg);
+	      ep->X_add_number += 4;
+	      macro_build (ep, s, fmt, coproc ? treg : treg + 1, -1,
+			   offset_reloc[0], offset_reloc[1], offset_reloc[2],
+			   breg);
+	    }
+	  break;
+	}
+
       if (offset_expr.X_op != O_symbol
 	  && offset_expr.X_op != O_constant)
 	{
@@ -9569,13 +9516,6 @@ macro (struct mips_cl_insn *ip, char *st
 	  as_bad (_("Number (0x%s) larger than 32 bits"), value);
 	}
 
-      /* Even on a big endian machine $fn comes before $fn+1.  We have
-	 to adjust when loading from memory.  We set coproc if we must
-	 load $fn+1 first.  */
-      /* Itbl support may require additional care here.  */
-      if (!target_big_endian)
-	coproc = 0;
-
       if (mips_pic == NO_PIC || offset_expr.X_op == O_constant)
 	{
 	  /* If this is a reference to a GP relative symbol, we want
@@ -9628,7 +9568,15 @@ macro (struct mips_cl_insn *ip, char *st
 	      offset_expr.X_add_number -= 4;
 	    }
 	  used_at = 1;
-	  macro_build_lui (&offset_expr, AT);
+	  if (offset_high_part (offset_expr.X_add_number, 16)
+	      != offset_high_part (offset_expr.X_add_number + 4, 16))
+	    {
+	      load_address (AT, &offset_expr, &used_at);
+	      offset_expr.X_op = O_constant;
+	      offset_expr.X_add_number = 0;
+	    }
+	  else
+	    macro_build_lui (&offset_expr, AT);
 	  if (breg != 0)
 	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
 	  /* Itbl support may require additional care here.  */
@@ -9768,36 +9716,13 @@ macro (struct mips_cl_insn *ip, char *st
 	abort ();
 
       break;
-
-    case M_LD_OB:
-      s = HAVE_64BIT_GPRS ? "ld" : "lw";
-      goto sd_ob;
-    case M_SD_OB:
-      s = HAVE_64BIT_GPRS ? "sd" : "sw";
-    sd_ob:
-      macro_build (&offset_expr, s, "t,o(b)", treg,
-		   -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
-		   breg);
-      if (!HAVE_64BIT_GPRS)
-	{
-	  offset_expr.X_add_number += 4;
-	  macro_build (&offset_expr, s, "t,o(b)", treg + 1,
-		       -1, offset_reloc[0], offset_reloc[1], offset_reloc[2],
-		       breg);
-	}
-      break;
-
 	
     case M_SAA_AB:
-      ab = 1;
-    case M_SAA_OB:
       s = "saa";
       offbits = 0;
       fmt = "t,(b)";
       goto ld_st;
     case M_SAAD_AB:
-      ab = 1;
-    case M_SAAD_OB:
       s = "saad";
       offbits = 0;
       fmt = "t,(b)";
@@ -10453,56 +10378,42 @@ macro (struct mips_cl_insn *ip, char *st
       end_noreorder ();
       break;
 
-    case M_ULH_A:
-      ab = 1;
-    case M_ULH:
+    case M_ULH_AB:
       s = "lb";
       s2 = "lbu";
       off = 1;
       goto uld_st;
-    case M_ULHU_A:
-      ab = 1;
-    case M_ULHU:
+    case M_ULHU_AB:
       s = "lbu";
       s2 = "lbu";
       off = 1;
       goto uld_st;
-    case M_ULW_A:
-      ab = 1;
-    case M_ULW:
+    case M_ULW_AB:
       s = "lwl";
       s2 = "lwr";
       offbits = (mips_opts.micromips ? 12 : 16);
       off = 3;
       goto uld_st;
-    case M_ULD_A:
-      ab = 1;
-    case M_ULD:
+    case M_ULD_AB:
       s = "ldl";
       s2 = "ldr";
       offbits = (mips_opts.micromips ? 12 : 16);
       off = 7;
       goto uld_st;
-    case M_USH_A:
-      ab = 1;
-    case M_USH:
+    case M_USH_AB:
       s = "sb";
       s2 = "sb";
       off = 1;
       ust = 1;
       goto uld_st;
-    case M_USW_A:
-      ab = 1;
-    case M_USW:
+    case M_USW_AB:
       s = "swl";
       s2 = "swr";
       offbits = (mips_opts.micromips ? 12 : 16);
       off = 3;
       ust = 1;
       goto uld_st;
-    case M_USD_A:
-      ab = 1;
-    case M_USD:
+    case M_USD_AB:
       s = "sdl";
       s2 = "sdr";
       offbits = (mips_opts.micromips ? 12 : 16);
@@ -10510,32 +10421,26 @@ macro (struct mips_cl_insn *ip, char *st
       ust = 1;
 
     uld_st:
-      if (!ab && offset_expr.X_add_number >= 0x8000 - off)
-	as_bad (_("Operand overflow"));
-
+      large_offset = !small_offset_p (off, align, offbits);
       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;
-	  ep = &expr1;
-	}
-      else if (offbits == 12
-	       && (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)))
+      if (large_offset)
 	{
 	  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]);
+	  if (small_offset_p (0, align, 16))
+	    macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", tempreg, breg, -1,
+			 offset_reloc[0], offset_reloc[1], offset_reloc[2]);
+	  else
+	    {
+	      load_address (tempreg, ep, &used_at);
+	      if (breg != 0)
+		macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
+			     tempreg, tempreg, breg);
+	    }
+	  offset_reloc[0] = BFD_RELOC_LO16;
+	  offset_reloc[1] = BFD_RELOC_UNUSED;
+	  offset_reloc[2] = BFD_RELOC_UNUSED;
 	  breg = tempreg;
 	  tempreg = treg;
 	  ep = &expr1;
@@ -10553,21 +10458,23 @@ macro (struct mips_cl_insn *ip, char *st
 
       if (!target_big_endian)
 	ep->X_add_number += off;
-      if (offbits != 12)
-	macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
-      else
+      if (offbits == 12)
 	macro_build (NULL, s, "t,~(b)",
 		     tempreg, (unsigned long) ep->X_add_number, breg);
+      else
+	macro_build (ep, s, "t,o(b)", tempreg, -1,
+		     offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       if (!target_big_endian)
 	ep->X_add_number -= off;
       else
 	ep->X_add_number += off;
-      if (offbits != 12)
-	macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
-      else
+      if (offbits == 12)
 	macro_build (NULL, s2, "t,~(b)",
 		     tempreg, (unsigned long) ep->X_add_number, breg);
+      else
+	macro_build (ep, s2, "t,o(b)", tempreg, -1,
+		     offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* If necessary, move the result in tempreg to the final destination.  */
       if (!ust && treg != tempreg)
@@ -10582,14 +10489,15 @@ macro (struct mips_cl_insn *ip, char *st
       used_at = 1;
       if (target_big_endian == ust)
 	ep->X_add_number += off;
-      tempreg = ust || ab ? treg : AT;
-      macro_build (ep, s, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+      tempreg = ust || large_offset ? treg : AT;
+      macro_build (ep, s, "t,o(b)", tempreg, -1,
+		   offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* For halfword transfers we need a temporary register to shuffle
          bytes.  Unfortunately for M_USH_A we have none available before
          the next store as AT holds the base address.  We deal with this
          case by clobbering TREG and then restoring it as with ULH.  */
-      tempreg = ust == ab ? treg : AT;
+      tempreg = ust == large_offset ? treg : AT;
       if (ust)
 	macro_build (NULL, "srl", SHFT_FMT, tempreg, treg, 8);
 
@@ -10597,21 +10505,23 @@ macro (struct mips_cl_insn *ip, char *st
 	ep->X_add_number -= off;
       else
 	ep->X_add_number += off;
-      macro_build (ep, s2, "t,o(b)", tempreg, BFD_RELOC_LO16, breg);
+      macro_build (ep, s2, "t,o(b)", tempreg, -1,
+		   offset_reloc[0], offset_reloc[1], offset_reloc[2], breg);
 
       /* For M_USH_A re-retrieve the LSB.  */
-      if (ust && ab)
+      if (ust && large_offset)
 	{
 	  if (target_big_endian)
 	    ep->X_add_number += off;
 	  else
 	    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, -1,
+		       offset_reloc[0], offset_reloc[1], offset_reloc[2], AT);
 	}
       /* For ULH and M_USH_A OR the LSB in.  */
-      if (!ust || ab)
+      if (!ust || large_offset)
 	{
-	  tempreg = !ab ? AT : treg;
+	  tempreg = !large_offset ? AT : treg;
 	  macro_build (NULL, "sll", SHFT_FMT, tempreg, tempreg, 8);
 	  macro_build (NULL, "or", "d,v,t", treg, treg, AT);
 	}
@@ -11416,6 +11326,16 @@ mips_ip (char *str, struct mips_cl_insn
 	  return;
 	}
 
+      imm_expr.X_op = O_absent;
+      imm2_expr.X_op = O_absent;
+      offset_expr.X_op = O_absent;
+      imm_reloc[0] = BFD_RELOC_UNUSED;
+      imm_reloc[1] = BFD_RELOC_UNUSED;
+      imm_reloc[2] = BFD_RELOC_UNUSED;
+      offset_reloc[0] = BFD_RELOC_UNUSED;
+      offset_reloc[1] = BFD_RELOC_UNUSED;
+      offset_reloc[2] = BFD_RELOC_UNUSED;
+
       create_insn (ip, insn);
       insn_error = NULL;
       argnum = 1;
@@ -12782,10 +12702,20 @@ mips_ip (char *str, struct mips_cl_insn
 	      continue;
 
 	    case 'A':
-	      my_getExpression (&offset_expr, s);
-	      normalize_address_expr (&offset_expr);
-	      *imm_reloc = BFD_RELOC_32;
-	      s = expr_end;
+	      /* If we expect a base register, 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 (args[1] == '(' && *s == '(' && strchr (s + 1, '(') == 0)
+		{
+		  offset_expr.X_op = O_constant;
+		  offset_expr.X_add_number = 0;
+		}
+	      else
+		{
+		  my_getSmallExpression (&offset_expr, offset_reloc, s);
+		  normalize_address_expr (&offset_expr);
+		  s = expr_end;
+		}
 	      continue;
 
 	    case 'F':

Attachment: testsuite.diff.bz2
Description: BZip2 compressed data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]